/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.cef.repository.adaptor;

import com.inspur.edp.cef.api.CefRtBeanUtil;
import com.inspur.edp.cef.api.RefObject;
import com.inspur.edp.cef.api.authority.AuthorityInfo;
import com.inspur.edp.cef.api.repository.*;
import com.inspur.edp.cef.api.repository.readerWriter.ICefReader;
import com.inspur.edp.cef.core.i18n.I18nResourceUtil;
import com.inspur.edp.cef.entity.UQConstraintMediate;
import com.inspur.edp.cef.entity.changeset.ModifyChangeDetail;
import com.inspur.edp.cef.entity.changeset.ValueObjModifyChangeDetail;
import com.inspur.edp.cef.entity.condition.*;
import com.inspur.edp.cef.entity.dependenceTemp.DataValidator;
import com.inspur.edp.cef.entity.dependenceTemp.Pagination;
import com.inspur.edp.cef.entity.entity.ICefData;
import com.inspur.edp.cef.entity.entity.IChildEntityData;
import com.inspur.edp.cef.entity.entity.IEntityData;
import com.inspur.edp.cef.entity.entity.IMultiLanguageData;
import com.inspur.edp.cef.entity.i18n.MultiLanguageInfo;
import com.inspur.edp.cef.entity.repository.DataSaveParameter;
import com.inspur.edp.cef.repository.adaptoritem.EntityRelationalReposAdaptor;
import com.inspur.edp.cef.repository.assembler.AbstractDataAdapterExtendInfo;
import com.inspur.edp.cef.repository.assembler.AssoCondition;
import com.inspur.edp.cef.repository.assembler.AssociationInfo;
import com.inspur.edp.cef.repository.dac.DacSaveContext;
import com.inspur.edp.cef.repository.dac.EntityDac;
import com.inspur.edp.cef.repository.dbcolumninfo.DbColumnInfo;
import com.inspur.edp.cef.repository.dbcolumninfo.DbColumnInfoCollection;
import com.inspur.edp.cef.repository.readerwriter.CefDataReader;
import com.inspur.edp.cef.repository.repo.BaseRootRepository;
import com.inspur.edp.cef.repository.utils.DatabaseUtil;
import com.inspur.edp.cef.repository.utils.FilterUtil;
import com.inspur.edp.cef.repository.utils.RepositoryUtil;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.ComplexUdtPropertyInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.DataTypePropertyInfo;
import com.inspur.edp.cef.spi.entity.resourceInfo.builinImpls.CefEntityResInfoImpl;
import com.inspur.edp.cef.spi.jsonser.base.StringUtils;
import io.iec.edp.caf.boot.context.CAFContext;
import io.iec.edp.caf.commons.dataaccess.DbType;
import io.iec.edp.caf.databaseobject.api.entity.DatabaseObjectType;
import io.iec.edp.caf.databaseobject.api.entity.TempTableContext;
import io.iec.edp.caf.databaseobject.api.service.IDatabaseObjectRtService;
import io.iec.edp.caf.i18n.framework.api.language.EcpLanguage;
import io.iec.edp.caf.runtime.config.CefBeanUtil;
import lombok.var;
import org.hibernate.jpa.TypedParameterValue;
import org.hibernate.type.StandardBasicTypes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.TemporalType;
import javax.transaction.Transactional;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

public abstract class EntityRelationalAdaptor extends BaseEntityAdaptor {
    protected static Logger logger = LoggerFactory.getLogger(EntityRelationalAdaptor.class);
    //    @PersistenceContext()
    protected EntityManager entityManager;
    private String authoritySql = " JOIN (%1$s) %2$s ON %3$s = %4$s";
    private String authorityTableAlias = "authorityTable";
    private String versionControlPropName;
    private String GetDataWithParentJoinSql = "select %1$s from %2$s %3$s %4$s";
    private DbColumnInfoCollection containColumns;
    private DbColumnInfoCollection extendContainColumns;
    private IDatabaseObjectRtService dboService;
    private String queryFields;
    private String queryTableName;
    private Boolean hasMultiLangCol;
    private HashMap<String, INestedRepository> nestedRepositories = new HashMap<>();
    private final Object netstRepositoryLock = new Object();
    protected EntityRelationalAdaptor() {
        this(true);
    }

    protected EntityRelationalAdaptor(boolean init) {
        super(init);
        containColumns = new DbColumnInfoCollection();
        if (init) {
            initColumns();
        }
        entityManager = CefBeanUtil.getEntityManager();
    }

    public EntityManager getEntityManager() {
        return entityManager;
    }


    protected abstract String getDboID();

    protected String getNodeCode() {
        return null;
    }

    //region VersionControl
    protected String getVersionControlPropName() {
        return versionControlPropName;
    }

    public HashMap<String, Date> getVersionControlValues(List<String> dataIds) {
        if (getVersionControlPropName() == null || getVersionControlPropName().equals("")) {
            return new HashMap<>();
        }
        String sql = String.format(getGetDataByIdsSql(), getContainColumns().getPrimaryKey().getDbColumnName() + "," + getVersionControlPropName(), getTableName(), "%1$s");
        sql = formatFiscalAndMultiLang(sql);
        int batchCount = 5000;
        HashMap<String, Date> dic = new HashMap<>();
        if(dataIds != null && dataIds.size() > batchCount){
            int times = dataIds.size()%batchCount == 0 ? dataIds.size()/batchCount : dataIds.size()/batchCount + 1;
            for(int i=1 ;i<= times;i++){
                int endIndex = i == times ? dataIds.size() : batchCount*i;
                List<String> tempList = dataIds.subList(batchCount* (i-1), endIndex);
                String sqlformat = String.format(sql, getInFilter(tempList));
                HashMap<String, Date> tempDic = convertVersionControlValues(sqlformat, tempList, null);
                dic.putAll(tempDic);
            }
        }
        else {
            String sqlformat = String.format(sql, getInFilter(dataIds));
            HashMap<String, Date> tempDic = convertVersionControlValues(sqlformat, dataIds, null);
            dic.putAll(tempDic);
        }

        return dic;
    }

    public Date getVersionControlValue(String dataId) {
        if (getVersionControlPropName() == null || getVersionControlPropName().equals("")) {
            return new Date(0);
        }
        String sql = String.format(getGetDataByIdSql(), getVersionControlPropName(), getTableName(), "?0 ");
        try {
            List<DbParameter> list = new ArrayList<DbParameter>();
            list.add(buildParam("ID", getContainColumns().getPrimaryKey().getColumnType(), dataId));
            Date value = convertVersionControlValue(sql, list);
            return value;
        } catch (Exception ex) {
            throw new RuntimeException(buildMessage(ex.getMessage()),ex);
        }
    }

    private List<Date> convertVersionControlValues(String sql, List<DbParameter> parameters) {
        Query query = buildQueryManager(sql, parameters);
        List<Object> resultSet = query.getResultList();
        List<Date> results = new ArrayList<Date>();
        resultSet.stream().forEach(item -> {
            var instance = new Date(0);
            if (item != null) {
                instance = (Date) item;
            }
            results.add(instance);
        });
        return results;
    }

    private HashMap<String, Date>  convertVersionControlValues(String sql, List<String> dataIds, List<DbParameter> parameters) {
        Query query = buildQueryManager(sql, parameters);
        HashMap<String, Date> dic = new HashMap<String, Date>();
        List<Object[]> resultSet = query.getResultList();
        List<Date> results = new ArrayList<Date>();
        for(String dataId: dataIds){
            List<Object[]> objs = resultSet.stream().filter(item->item[0].equals(dataId)).collect(Collectors.toList());
            if(objs != null && objs.size() >0){
                var instance = new Date(0);
                if (objs.get(0)[1] != null) {
                    instance = (Date) objs.get(0)[1];
                }
                dic.put(dataId, instance);
            }
        }
        return dic;
    }

    private Date convertVersionControlValue(String sql, List<DbParameter> parameters) {
        Query query = buildQueryManager(sql, parameters);
        List resultSet = query.getResultList();
        if (resultSet == null || resultSet.isEmpty()) {
            throw new RuntimeException("数据不存在或已被删除");
        } else {
            Object result = resultSet.get(0);
            return result == null ? new Date(0) : (Date) result ;
        }
    }

    //endregion
    // region Query
    @Override
    public List<IEntityData> query(EntityFilter filter, ArrayList<AuthorityInfo> authorities) {
        buildLogicDeleteCondition(filter);
        if (filter.getIsUsePagination()) {
            return queryWithPagination(filter, authorities);
        } else {
            return queryWithoutPagination(filter, authorities);
        }

    }

    @Override
    public void setDataAdapterExtendInfos(ArrayList<AbstractDataAdapterExtendInfo> infos) {
        super.setDataAdapterExtendInfos(infos);
        extendContainColumns = new DbColumnInfoCollection();
        for (AbstractDataAdapterExtendInfo info:infos) {
            if(info.getDbColumnInfos() ==null)
                continue;
            extendContainColumns.addRange(info.getDbColumnInfos());
        }
    }
    //region TODO 应该不需要生成
    protected abstract boolean hasPropColumnMappping();

    protected abstract HashMap<String, Integer> getPropertyColumnMapping();

    protected abstract void setPropertyColumnMapping(HashMap<String, Integer> mapping);
    //endregion

    public HashMap<String, String> getAssosPropDBMapping(String propName)
    {
        return new HashMap<String, String>();
    }

    private HashMap<String, Integer> innerGetPropertyColumnMapping() {
        HashMap<String, Integer> mapping = getPropertyColumnMapping();
//        Integer index = mapping.size() - 1;
//        List<String> mappingColumns = new ArrayList<>();
//        for (AbstractDataAdapterExtendInfo extendInfo : getDataAdapterExtendInfos()) {
//            extendInfo.setQueryFields(mappingColumns);
//        }
//        if (mappingColumns.size() == 0)
//            return mapping;
//        HashMap<String, Integer> newMapping = new HashMap<>(mapping);
//        for (String extendInfo : mappingColumns) {
//            newMapping.put(extendInfo, index++);
//        }
//        return newMapping;
        return mapping;
    }

    private List<IEntityData> queryWithoutPagination(EntityFilter filter, ArrayList<AuthorityInfo> authorities) {
        String tableName = getQueryTableNameWithAuthority(authorities,filter);
        StringBuilder sql = new StringBuilder();
        //region TODO getQueryFields 需要整理，调用地方太多
        sql.append(String.format("SELECT %1$s FROM %2$s ", getQueryFields(filter), tableName));
        //endregion
        ArrayList<DbParameter> parameter = new ArrayList<DbParameter>();
        String condition = buildWhereCondition(getDB(), filter.getFilterConditions(), parameter);
        String sort = buildOrderByCondition(filter.getSortConditions());
        if (condition != null && condition.length() > 0) {
            sql.append(String.format(" WHERE %1$s", condition));
        }
        if (sort != null && sort.length() > 0) {
            sql.append(String.format(" Order By %1$s", sort));
        }
        try {
            return getDatas(formatMultiLang(sql.toString()), parameter);
        } catch (java.lang.Exception e) {
//            System.out.println("执行查询出错，Sql语句：" + sql.toString() + ".");
//            StringBuilder sbParam = new StringBuilder();
//            for (DbParameter item : parameter) {
//                sbParam.append(item.getParamName() + ":" + item.getValue() + ";");
//            }
//            System.out.println("参数信息如下：" + sbParam.toString());
            throw new RuntimeException(e);
        }
    }

    private List<IEntityData> queryWithPagination(EntityFilter filter, ArrayList<AuthorityInfo> authorities) {

        String tableName = getQueryTableNameWithAuthority(authorities,filter);
        ArrayList<DbParameter> parameter = new ArrayList<DbParameter>();
        String condition = buildWhereCondition(getDB(), filter.getFilterConditions(), parameter);
        String sort = buildOrderByCondition(filter.getSortConditions());
        Pagination pagination = filter.getPagination();
        try {
            RefObject<Pagination> tempRef_pagination = new RefObject<Pagination>(pagination);
//			return getDatas(String.format("SELECT %1$s FROM %2$s WHERE "));
            List<IEntityData> tempVar = DatabaseUtil.getPaginationData(tableName, getTableName(), formatMultiLang(getQueryFields(filter)),
                    getWrappedTableAlias().concat(".").concat(getContainColumns().getPrimaryKey().getDbColumnName()),
                    condition,
                    sort,
                    parameter,
                    tempRef_pagination,
                    this, isTableView());
            pagination = tempRef_pagination.argvalue;
            return tempVar;
        } catch (Exception e) {
            throw new RuntimeException("执行分页取数失败", e);
        }
    }

    private String getQueryFields(EntityFilter filter) {
        if (filter != null && filter.getFieldsFilter() != null && filter.getFieldsFilter().isUseFieldsCondition())
            return buildQueryColumns(true, filter.getFieldsFilter().getFilterFields());
        return buildQueryColumns(false, null);
    }

    private String getQueryFields(AdaptorRetrieveParam adaptorRetrieveParam) {
        EntityFilter filter = adaptorRetrieveParam.getEntityfilter(getNodeCode());
        // 构造非多语列列名
        String fields = getQueryFields(filter);
        if (adaptorRetrieveParam == null || !adaptorRetrieveParam.isEnableMultiLanguage()) {
            return fields;
        }
        String multiLangFields = buildQueryColumns_MultiLanguage(filter);
        if (multiLangFields.length() > 0 && fields.length() > 0) {
            fields = fields.concat("," + multiLangFields);
        }
        queryFields = fields;
        return fields;
    }

    private String getQueryTableNameWithAuthority(ArrayList<AuthorityInfo> authorities,EntityFilter filter) {
        String tempQueryTableName="";
        if(filter!=null&&filter.getFieldsFilter()!=null&&filter.getFieldsFilter().isUseFieldsCondition())
        {
            tempQueryTableName=getQueryTableNameByFields(filter);
        }
        else {
            initQueryTableName();
            tempQueryTableName=queryTableName;
        }

        //String tableName = queryTableName;
        String authority = getAuthoritySql(authorities);
        return tempQueryTableName + authority;
    }

    private String getQueryTableNameByFields(EntityFilter filter)
    {
        ArrayList<AssociationInfo> associationInfos=new ArrayList<>();
        for(AssociationInfo associationInfo:getAssociationInfos())
        {
            if(filter.getFieldsFilter().getFilterFields().contains(associationInfo.getSourceColumn()))
            {associationInfos.add(associationInfo);
            }
        }
        return getTableNamesWithAssociationInfo(associationInfos, null);
    }

    private String getAuthoritySql(ArrayList<AuthorityInfo> authorities) {
        if (authorities == null || authorities.size() < 1) {
            return "";
        }
        StringBuilder authorityBuilder = new StringBuilder();
        for (int i = 1; i < authorities.size() + 1; i++) {
            AuthorityInfo info = authorities.get(i - 1);
            String aliasName = authorityTableAlias + i;
            String fieldName = trans2DbColumnWithAlias(info.getFieldName());
            String sourceFieldName = aliasName + "." + info.getSourceFieldName();

            authorityBuilder.append(String.format(authoritySql, info.getAuthoritySql(), aliasName, fieldName, sourceFieldName));
        }

        return authorityBuilder.toString();
    }

    // region buildWhereCondition
    private String buildWhereCondition(Connection db, ArrayList<FilterCondition> filter, ArrayList<DbParameter> parameter) {
        //DynamicParameters
        String beCondition = getDefaultCondition(db, parameter);

        String externalCondition = parseFilterCondition(getDB(), filter, parameter, parameter.size(),false);

        String tenantCondition = getTenantCondition();

        String condition = String.format("%1$s%2$s%3$s", beCondition, externalCondition, tenantCondition);
        if (condition.startsWith(" AND ")) {
            condition = condition.substring(4);
        }

        if (condition == null || condition.length() == 0) {
            return condition;
        }
        return formatMultiLang(condition);
    }

    private void buildLogicDeleteCondition(EntityFilter entityFilter){
        if(!getLogicDeleteInfo().isEnableLogicDelete())
            return;
        if(entityFilter == null)
            entityFilter = new EntityFilter();
        if(entityFilter.getFilterConditions() == null){
            ArrayList<FilterCondition> filterConditions = new ArrayList<>();
            entityFilter.setFilterConditions(filterConditions);
        }
        if(entityFilter.getFilterConditions().size()>0){//修改最后一个的relation符号
            entityFilter.getFilterConditions().get(entityFilter.getFilterConditions().size() - 1).setRelation(ExpressRelationType.And);
        }
        FilterCondition filterCondition = new FilterCondition();
        filterCondition.setValue("0");
        filterCondition.setFilterField(getLogicDeleteInfo().getLabelId());
        filterCondition.setCompare(ExpressCompareType.Equal);
        entityFilter.getFilterConditions().add(filterCondition);
    }

    private String getDefaultCondition(Connection db, ArrayList<DbParameter> parameter) {
        ArrayList<FilterCondition> filterConditions = getDefaultFilterCondition();
        if (filterConditions == null || filterConditions.size() < 1) {
            return "";
        }
        StringBuilder conditionBuilder = new StringBuilder("(");
        int paramNum = parameter.size();
        for (FilterCondition filterItem : filterConditions) {
            String columnName ="";
            if(filterItem.getFilterField()!=null&&filterItem.getFilterField().isEmpty()==false)
                columnName=trans2DbColumnWithAlias(filterItem.getFilterField());

            GspDbDataType dataType = getDataType(filterItem.getFilterField());
            RefObject<Integer> tempRef_paramNum = new RefObject<Integer>(paramNum);
            conditionBuilder.append(FilterUtil.parseFilterCondition(filterItem, columnName, parameter, db, dataType, tempRef_paramNum, getTypeTransProcesser(filterItem.getFilterField())));
            paramNum = tempRef_paramNum.argvalue;
        }

        conditionBuilder.append(")");

        return conditionBuilder.toString();
    }

    private String getTenantCondition() {
        //String tenantCondition = TenantUtil.GetCondition(TableAlias);
        //if (!String.IsNullOrEmpty(tenantCondition))
        //    return " AND (" + tenantCondition + ")";
        return "";
    }

    public final ITypeTransProcesser getTypeTransProcesser(String fieldName) {
        //跟之前一致
        if (!getAllContainColumns().contains(fieldName)) {
            throw new RuntimeException("Error Field Name");
        }
        //Func<FilterCondition, IGSPDatabase, object> processer = ContainColumns[fieldName].typetransprocesser;
        ITypeTransProcesser processer = getAllContainColumns().getItem(fieldName).getTypeTransProcesser();
        if (processer == null) {
            throw new RuntimeException("字段" + fieldName + "没有初始化Processer方法，解析失败");
        }
        return processer;
    }

    // endregion

    private String buildOrderByCondition(ArrayList<SortCondition> orderByConditions) {
        ArrayList<SortCondition> defaultSortCondition = getDefaultSortCondition();
        String defaultSort = buildDefaultOrderByCondition(defaultSortCondition);
        StringBuilder orderByBuilder = new StringBuilder(defaultSort);
        if (orderByConditions != null && orderByConditions.size() > 0) {
            ArrayList<SortCondition> sortConditions = transSortCondition(orderByConditions);
            for (SortCondition orderByItem : sortConditions) {
                if (orderByBuilder.toString() != null && !"".equals(orderByBuilder.toString())) {
                    orderByBuilder.append(", ");
                }
                String filedName = trans2DbColumnWithAlias(orderByItem.getSortField());
                orderByBuilder.append(orderByItem.trans2Sql(filedName));
            }
        }

        if (orderByBuilder.toString() == null || orderByBuilder.toString().length() == 0) {
            return getWrappedTableAlias() + "." + getContainColumns().getPrimaryKey().getDbColumnName() + " ASC";
        }
        return formatMultiLang(orderByBuilder.toString());
    }

    private ArrayList<SortCondition> transSortCondition(ArrayList<SortCondition> orderByConditions) {
        HashMap<String, SortCondition> sortConditions = new HashMap<String, SortCondition>();
        ArrayList<SortCondition> sorts = new ArrayList<SortCondition>();
        for (SortCondition sortCondition : orderByConditions) {
            if (!sortConditions.containsKey(sortCondition.getSortField().toLowerCase())) {
                sortConditions.put(sortCondition.getSortField().toLowerCase(), sortCondition);
                sorts.add(sortCondition);
            }
        }

        return sorts;
    }

    private String buildDefaultOrderByCondition(ArrayList<SortCondition> sortConditions) {
        StringBuilder orderByBuilder = new StringBuilder();
        if (sortConditions != null && sortConditions.size() > 0) {
            for (SortCondition orderByItem : sortConditions) {
                if (orderByBuilder.toString() != null && !orderByBuilder.toString().equals("")) {
                    orderByBuilder.append(", ");
                }
                String filedName = trans2DbColumnWithAlias(orderByItem.getSortField());
                orderByBuilder.append(orderByItem.trans2Sql(filedName));
            }
        }

        return String.valueOf(orderByBuilder);
    }

    public String getInIDsFilter(List<String> dataIds) {
        return String.format(" where %1$s.%2$s IN %3$s", getWrappedTableAlias(), getContainColumns().getPrimaryKey().getDbColumnName(), FilterUtil.buildInCondition(dataIds.toArray(new String[]{}), false,getWrappedTableAlias()+"."+getContainColumns().getPrimaryKey().getDbColumnName()));
    }

    //获取分批in条件
    public List<String> getBatchInIDsFilter(List<String> dataIds) {
        int batchCount = 5000;
        List<String> batchIns = new ArrayList<>();
        if(dataIds != null && dataIds.size() > batchCount){
            int times = dataIds.size()%batchCount == 0 ? dataIds.size()/batchCount : dataIds.size()/batchCount + 1;
            for(int i=1 ;i<= times;i++){
                int endIndex = i == times ? dataIds.size() : batchCount*i;
                List<String> tempList = dataIds.subList(batchCount* (i-1), endIndex);
                batchIns.add(String.format(" where %1$s.%2$s IN %3$s", getWrappedTableAlias(), getContainColumns().getPrimaryKey().getDbColumnName(), FilterUtil.buildInCondition(tempList.toArray(new String[]{}), false,getWrappedTableAlias()+"."+getContainColumns().getPrimaryKey().getDbColumnName())));
            }
        }
        else {
            batchIns.add(String.format(" where %1$s.%2$s IN %3$s", getWrappedTableAlias(), getContainColumns().getPrimaryKey().getDbColumnName(), FilterUtil.buildInCondition(dataIds.toArray(new String[]{}), false,getWrappedTableAlias()+"."+getContainColumns().getPrimaryKey().getDbColumnName())));
        }
        return batchIns;
    }

    public String getInFilter(List<String> dataIds) {
        return FilterUtil.buildInCondition(dataIds.toArray(new String[]{}), false,getWrappedTableAlias()+"."+getContainColumns().getPrimaryKey().getDbColumnName());
    }

    /**
     *
     * @param dataIds
     * @param propName 不带别名.
     * @return
     */
    public String getInFilter(List<String> dataIds, String propName) {
        return FilterUtil.buildInCondition(dataIds.toArray(new String[]{}), false,propName);
    }

    public String getIDFilter() {
        return String.format(" where %1$s.%2$s=", getWrappedTableAlias(), getContainColumns().getPrimaryKey().getDbColumnName()) + "?0";
    }

    public List<IChildEntityData> getDataWithParentJoinIds(String joinInfo, String condition
            , ArrayList<SortCondition> orderByCondition, ArrayList<String> tableAlias, List<DbParameter> dbPars) {
        return this.getDataWithParentJoinIds(joinInfo, condition, orderByCondition, tableAlias, dbPars, null);
    }


    public List<IChildEntityData> getDataWithParentJoinIds(String joinInfo, List<String> conditions
            , ArrayList<SortCondition> orderByCondition, ArrayList<String> tableAlias, List<DbParameter> dbPars, AdaptorRetrieveParam adaptorRetrieveParam) {
        initQueryTableNameWithParentAlias(tableAlias, adaptorRetrieveParam);
        List<IChildEntityData> childDatas = new ArrayList<IChildEntityData>();
        //todo conidtions过来必须有值
        if(conditions != null && conditions.size() >0){
            for(String condition :conditions){
                List<DbParameter> tempdbPars = new ArrayList<>();
                if(getLogicDeleteInfo().isEnableLogicDelete()){
                    if(dbPars != null && dbPars.size() > 0){
                        tempdbPars.addAll(dbPars);
                    }
                    tempdbPars.add(buildParam(getLogicDeleteInfo().getLabelId(), GspDbDataType.Char, "0"));
                    condition += " and "+getWrappedTableAlias()+"." + getLogicDeleteInfo().getLabelId() +  " = ?" + (tempdbPars.size() - 1);
                }
                String sql = String.format(GetDataWithParentJoinSql, getQueryFields(adaptorRetrieveParam), queryTableName, joinInfo, condition);
                sql += buildRetrieveOrderBy(orderByCondition);
                sql = formatFiscalAndMultiLang(sql);
                List<IEntityData> datas = getDatas(sql, tempdbPars, adaptorRetrieveParam);
                if (datas == null)
                    return null;
                for (IEntityData data : datas) {
                    childDatas.add((IChildEntityData) data);
                }
            }
        }
        return childDatas;
    }

    public List<IChildEntityData> getDataWithParentJoinIds(String joinInfo, String condition
            , ArrayList<SortCondition> orderByCondition, ArrayList<String> tableAlias, List<DbParameter> dbPars, AdaptorRetrieveParam adaptorRetrieveParam) {
        initQueryTableNameWithParentAlias(tableAlias, adaptorRetrieveParam);
        if(getLogicDeleteInfo().isEnableLogicDelete()){
            if(dbPars == null)
                dbPars = new ArrayList<>();
            dbPars.add(buildParam(getLogicDeleteInfo().getLabelId(), GspDbDataType.Char, "0"));
            condition += " and "+getWrappedTableAlias()+"." + getLogicDeleteInfo().getLabelId() +  " = ?" + (dbPars.size() - 1);
        }
        String sql = String.format(GetDataWithParentJoinSql, getQueryFields(adaptorRetrieveParam), queryTableName, joinInfo, condition);
        sql += buildRetrieveOrderBy(orderByCondition);
        sql = formatFiscalAndMultiLang(sql);
        List<IEntityData> datas = getDatas(sql, dbPars, adaptorRetrieveParam);
        if (datas == null)
            return null;
        List<IChildEntityData> childDatas = new ArrayList<IChildEntityData>();
        for (IEntityData data : datas) {
            childDatas.add((IChildEntityData) data);
        }
        return childDatas;
    }

    private String buildRetrieveOrderBy(ArrayList<SortCondition> orderBys) {
        if (orderBys == null || orderBys.size() < 1) {
            return "";
        }
        return " ORDER BY " + buildDefaultOrderByCondition(orderBys);
    }

    public final List<IEntityData> getDataWithParentJoinId(String joinInfo, String condition, String rootId) {
        String sql = String.format(GetDataWithParentJoinSql, queryFields, innerGetTableName(), getWrappedTableAlias(), joinInfo + " " + condition);
        ArrayList<DbParameter> parameters = new ArrayList<DbParameter>();
        parameters.add(new DbParameter("rootId", GspDbDataType.VarChar, rootId));
        return getDatas(sql, parameters);
    }

    public DbColumnInfoCollection getContainColumns() {
        return containColumns;
    }

    public DbColumnInfoCollection getAllContainColumns() {

        if(extendContainColumns != null && extendContainColumns.getCount() >0){
            DbColumnInfoCollection col = new DbColumnInfoCollection();
            col.addRange(getContainColumns());
            col.addRange(extendContainColumns);
            return col;
        }
        return getContainColumns();
    }

    protected abstract void initColumns();

    protected abstract ArrayList<FilterCondition> getDefaultFilterCondition();

    protected abstract ArrayList<SortCondition> getDefaultSortCondition();

    private void setParameters(PreparedStatement statement, List<DbParameter> parameters) throws SQLException {
        int index = 0;
        if (parameters == null || parameters.size() == 0)
            return;
        for (DbParameter parameter : parameters) {
            switch (parameter.getDataType()) {
                case VarChar:
                case Char:
                case NChar:
                case NVarChar:
                case Clob:
                case NClob:
                    statement.setString(index++, (String) parameter.getValue());
                    break;
                case Int:
                    statement.setInt(index++, (Integer) parameter.getValue());
                    break;
                case Decimal:
                    statement.setBigDecimal(index++, (BigDecimal) parameter.getValue());
                    break;
            }
        }
    }

    /**
     * 检索超过1W条数据,分拼执行合并结果
     * @param sql
     * @param dataIds
     * @return
     */
    public ArrayList<IEntityData> getDatasBatch(String sql, List<String> dataIds) {
        int batchCount = 5000;
        ArrayList<IEntityData> datas = new ArrayList<>();
        if(dataIds != null && dataIds.size() > batchCount){
            int times = dataIds.size()%batchCount == 0 ? dataIds.size()/batchCount : dataIds.size()/batchCount + 1;
            for(int i=1 ;i<= times;i++){
                int endIndex = i == times ? dataIds.size() : batchCount*i;
                List<String> tempList = dataIds.subList(batchCount* (i-1), endIndex);
                ArrayList<IEntityData> tempListData = getDatas(String.format(sql, getInFilter(tempList)), null);
                if(tempListData != null && tempListData.size() > 0){
                    datas.addAll(tempListData);
                }
            }
            return datas;
        }
        else {
            return this.getDatas(String.format(sql, getInFilter(dataIds)), null, new AdaptorRetrieveParam(null));
        }
    }

    public ArrayList<IEntityData> getDatas(String sql, List<DbParameter> parameters) {
        return this.getDatas(sql,parameters,new AdaptorRetrieveParam(null));
    }


    private ArrayList<IEntityData> getDatas(String sql, List<DbParameter> parameters,
                                            AdaptorRetrieveParam param) {
        Query query = buildQueryManager(sql, parameters);
        List<Object[]> resultSet = null;
        try {
            resultSet = query.getResultList();
        } catch (Exception ex) {
            logger.error("tablealias:" + getTableAlias() + " 出错sql:" + sql);
            throw ex;
        }
        return innerGetDatas(resultSet, param);
    }

    public List<IEntityData> getDatasInPagination(List<Object[]> resultSet) {
        return innerGetDatas(resultSet);
    }

    public ArrayList<IEntityData> innerGetDatas(List<Object[]> resultSet) {
        return this.innerGetDatas(resultSet, null);
    }

    private ArrayList<IEntityData> innerGetDatas(List<Object[]> resultSet, AdaptorRetrieveParam param) {
        ArrayList<IEntityData> results = new ArrayList<IEntityData>();
        HashMap<String, Integer> mapping =filteredPropDbIndexMapping;
        if(mapping==null)
            mapping=getPropertyColumnMapping();

        for (Object[] result : resultSet) {
            IEntityData instance = createEntityInstance(new CefDataReader(result, mapping), param);
            results.add(instance);
        }
        return results;
    }

    public final IEntityData createEntityInstance(ICefReader reader) {
        return this.createEntityInstance(reader, null);
    }

    private IEntityData createEntityInstance(ICefReader reader, AdaptorRetrieveParam pram) {
        ICefData tempVar = createInstance(reader);
        IEntityData data = (IEntityData) tempVar;
        for (AbstractDataAdapterExtendInfo extendInfo : getDataAdapterExtendInfos()) {
            extendInfo.setEntityPropertiesFromDal(reader, data);
        }
        // 处理多语列，赋值至ICefDataBase.MultiLanguageInfos
        if (pram != null && pram.isEnableMultiLanguage() && tempVar instanceof IMultiLanguageData) {
            IMultiLanguageData cefDataBase = (IMultiLanguageData) tempVar;
            Map<String, MultiLanguageInfo> resultInfos = cefDataBase.getMultiLanguageInfos();
            DbColumnInfoCollection columnInfos = this.getMultiLanguageColumnInfos();
            this.getMultiLanguageAlias().forEach((alias, multiLangColumnInfo) -> {
                if (reader.hasProperty(alias)) {
                    DbColumnInfo currentPropInfo = columnInfos
                            .getItem(multiLangColumnInfo.getColumnName());
                    if (currentPropInfo != null && currentPropInfo.getIsUdtElement()) {
                        // 多语控件不支持UDT
                        return;
                    }
                    String labelId =
                            multiLangColumnInfo.getColumnName() + MultiLanguageInfo.MULTILANGUAGETOKEN;
                    if (!resultInfos.containsKey(labelId)) {
                        resultInfos.put(labelId, new MultiLanguageInfo());
                    }
                    MultiLanguageInfo info = resultInfos.get(labelId);
                    info.setPropName(labelId);
                    // dm数据库获取数据需处理
                    Object currentAliasValue =
                            currentPropInfo.getColumnType().equals(GspDbDataType.NClob) ? getClobValue(reader
                                    .readValue(alias)) : reader.readValue(alias);
                    info.getPropValueMap()
                            .put(multiLangColumnInfo.getLanguageInfo().getCode(), currentAliasValue);
                }
            });
        }
        return (IEntityData) ((tempVar instanceof IEntityData) ? tempVar : null);
    }

    private IDatabaseObjectRtService getDboService() {
        return CefRtBeanUtil.getDboRtService();
    }

    public boolean isTableView(){
        return getDboService().getDatabaseObject(getDboID()).getType() == DatabaseObjectType.View;
    }

    public final String innerGetTableName() {
        try{
            return getDboService().getTableNameWithDimensionValue(getDboID(), getVars());
        }catch (Exception e){
            throw new RuntimeException("Be["+getConfigId()+"]中节点["+getNodeCode()+"]对应的dbo获取失败, 请联系dbo相关开发处理",e);
        }

    }

    public final List<String> innerGetTableNames() {
        try{
            return getDboService().getTableNamesWithDimensionValues(getDboID(), null);
        }catch (Exception e){
            throw new RuntimeException("Be["+getConfigId()+"]中节点["+getNodeCode()+"]对应的dbo获取失败, 请联系dbo相关开发处理",e);
        }

    }

    public final String getTableNameByDimensions(HashMap<String, String> dimensions) {
        return getDboService().getTableNameWithDimensionValue(getDboID(), dimensions);
    }

//    private String getQueryFields() {
//        String fields = queryFields;
//        for (AbstractDataAdapterExtendInfo extendInfo : getDataAdapterExtendInfos()) {
//           fields += extendInfo.getQueryFields();
//        }
//        return fields;
//    }

    public abstract String getPrimaryKey();

    public abstract String getTableAlias();

    //获取转换后的别名
    public String getWrappedTableAlias(){
        return KeyWordsManager.getTableAlias(getTableAlias());
    }

    public String getWrappedTableAlias(boolean ignoreKeyWords){
        return KeyWordsManager.getTableAlias(getTableAlias(), ignoreKeyWords);
    }

    public abstract void setTableAlias(String value);

    //protected abstract String DefaultSort { get; }
    protected abstract String getConfigId();

    ///#region initQueryTableName
    private void initQueryTableName() {
        //if (!String.IsNullOrEmpty(queryTableName))
        //    return;
        ////跟之前一致，并且在当前实例上做缓存。
        //queryTableName = getTableNamesWithAssociationInfo(AssociationInfos, null);
        //buildQueryColumns();
        initQueryTableNameWithParentAlias(null);
    }

    private void initQueryTableNameWithParentAlias(ArrayList<String> alias) {
        this.initQueryTableNameWithParentAlias(alias, new AdaptorRetrieveParam(null));
    }

    private void initQueryTableNameWithParentAlias(ArrayList<String> alias, AdaptorRetrieveParam adaptorRetrieveParam) {
        if (queryTableName != null && queryTableName.length() > 0) {
            return;
        }
        //跟之前一致，并且在当前实例上做缓存。
        queryTableName = getTableNamesWithAssociationInfo(getAssociationInfos(), alias);
        String fields = buildQueryColumns(false, null);
        if (adaptorRetrieveParam != null && adaptorRetrieveParam.isEnableMultiLanguage()) {
            String multiLangFields = buildQueryColumns_MultiLanguage(adaptorRetrieveParam.getEntityfilter(getNodeCode()));
            if (multiLangFields.length() > 0 && fields.length() > 0) {
                fields = fields.concat("," + multiLangFields);
            }
        }
        queryFields = fields;
    }

    // endregion

    public void buildQueryColumns()
    {
        buildQueryColumns(false,null);
    }
    private String buildExtendQueryColumns(EntityFilter filter){
        if (filter != null && filter.getFieldsFilter() != null && filter.getFieldsFilter().isUseFieldsCondition()){
            return buildExtendQueryColumns(true, filter.getFieldsFilter().getFilterFields());
        }
        return buildExtendQueryColumns(false, null);
    }
    public String buildExtendQueryColumns(boolean usePropertyFilter,List<String> filterProperties) {
        //跟之前一致，并且在当前实例上做缓存。
        StringBuilder columns = new StringBuilder();
        boolean hasPropDBIndexMapping = hasPropColumnMappping();
        hasPropDBIndexMapping=false;
        HashMap<String, Integer> mapping = null;
        if (hasPropDBIndexMapping == false) {
            mapping = new HashMap<String, Integer>();
        }
        int index = 0;

        index = buildQueryColumns(usePropertyFilter,filterProperties,getContainColumns(), columns, mapping, hasPropDBIndexMapping, index);
        if (extendContainColumns != null)
            buildQueryColumns(usePropertyFilter,filterProperties,extendContainColumns, columns, mapping, hasPropDBIndexMapping, index);

        if (hasPropDBIndexMapping == false) {
            setPropertyColumnMapping(mapping);
        }

        filteredPropDbIndexMapping=mapping;
        queryFields = columns.toString();
        return queryFields;
    }
    public String buildQueryColumns(boolean usePropertyFilter,List<String> filterProperties) {
        //跟之前一致，并且在当前实例上做缓存。
        StringBuilder columns = new StringBuilder();
        boolean hasPropDBIndexMapping = hasPropColumnMappping();
        hasPropDBIndexMapping=false;
        HashMap<String, Integer> mapping = null;
        if (hasPropDBIndexMapping == false) {
            mapping = new HashMap<String, Integer>();
        }
        int index = 0;

        index = buildQueryColumns(usePropertyFilter,filterProperties,getContainColumns(), columns, mapping, hasPropDBIndexMapping, index);
        if (extendContainColumns != null)
            buildQueryColumns(usePropertyFilter,filterProperties,extendContainColumns, columns, mapping, hasPropDBIndexMapping, index);

        if (hasPropDBIndexMapping == false) {
            setPropertyColumnMapping(mapping);
        }

        filteredPropDbIndexMapping=mapping;
        queryFields = columns.toString();
        return queryFields;
    }
    private HashMap<String, Integer> filteredPropDbIndexMapping=null;

    private int buildQueryColumns(boolean usePropertyFilter,List<String> filterProperties,
                                  DbColumnInfoCollection columnCollection,
                                  StringBuilder columns,
                                  HashMap<String, Integer> mapping,
                                  boolean hasPropDBIndexMapping,
                                  int index) {
        boolean containColumns = columns.length() > 0;
        if (usePropertyFilter) {
            for (DbColumnInfo containColumn : columnCollection) {
                if (filterProperties.contains(containColumn.getColumnName()) == false)
                {
                    if(containColumn.getIsAssociateRefElement()&&filterProperties.contains(containColumn.getBelongElementLabel()))
                    {}
                    else if (containColumn.getBelongElementLabel() != null && containColumn.getBelongElementLabel().isEmpty() == false && filterProperties.contains(containColumn.getBelongElementLabel())) {
                    }
                    else
                        continue;
                }

                if (containColumns) {
                    columns.append(",");
                }
                columns.append(trans2DbColumnWithAlias(containColumn.getColumnName())).append(" AS ").append(containColumn.getAliasName(index));

                containColumns = true;
                if (hasPropDBIndexMapping == false) {
                    mapping.put(containColumn.getColumnName(), index++);
                }
            }
        } else {
            for (DbColumnInfo containColumn : columnCollection) {
                if (containColumns) {
                    columns.append(",");
                }
                columns.append(trans2DbColumnWithAlias(containColumn.getColumnName())).append(" AS ").append(containColumn.getAliasName(index));
                containColumns = true;
                if (hasPropDBIndexMapping == false) {
                    mapping.put(containColumn.getColumnName(), index++);
                }
            }
        }
        return index;
    }
    // endregion

    // region MultiLanguageInfo

    private DbColumnInfoCollection multiLanguageColumnInfos;
    private Map<String, MultiLangColumnInfo> multiLanguageAlias;//<Key:国际化后缀别名 Name_CHS,Value:字段标签Name>

    private DbColumnInfoCollection getMultiLanguageColumnInfos() {
        //region TODO multiLanguageColumnInfos可以缓存起来，没必要每次都new
        this.multiLanguageColumnInfos = new DbColumnInfoCollection();
        //endregion
        for (DbColumnInfo col : getContainColumns()) {
            if (col.getIsMultiLang() && !col.getIsUdtElement()) {
                this.multiLanguageColumnInfos.add(col);
                continue;
            }
        }
        return this.multiLanguageColumnInfos;
    }

    //
    private Map<String, MultiLangColumnInfo> getMultiLanguageAlias() {
        if (this.multiLanguageAlias != null) {
            return this.multiLanguageAlias;
        }
        this.multiLanguageAlias = new HashMap<>();
        List<EcpLanguage> currentEnableLanguages = RepositoryUtil.getCurrentEnabledLanguages();
        this.getMultiLanguageColumnInfos().forEach(
                columnInfo -> {
                    currentEnableLanguages.forEach(language -> {
                        MultiLangColumnInfo info = new MultiLangColumnInfo();
                        String alias = RepositoryUtil.FormatMuliLangColumnName(columnInfo.getColumnName(), language);
                        info.setColumnName(columnInfo.getColumnName());
                        info.setLanguageInfo(language);
                        this.multiLanguageAlias.put(alias, info);
                    });
                }
        );
        return this.multiLanguageAlias;
    }

    /**
     * 构建多语相关的列名 TableName.Name_CHS as Name_CHS
     *
     * @return
     */
    private String buildQueryColumns_MultiLanguage(EntityFilter filter) {
        DbColumnInfoCollection collection = this.getMultiLanguageColumnInfos();
        // 无多语字段
        if (collection.getCount() == 0) {
            return "";
        }

        StringBuilder columns = new StringBuilder();
        HashMap<String, Integer> currentIndexMap = getPropertyColumnMapping();
        if (currentIndexMap == null) {
            throw new RuntimeException("当前PropertyColumnMapping为空");
        }

        List<EcpLanguage> currentEnableLanguages = RepositoryUtil.getCurrentEnabledLanguages();
        for (DbColumnInfo columnInfo : collection) {
            // 使用过滤，且不包含，此处不考虑关联带出字段
            if (filter != null && !filter.getFieldsFilter().getFilterFields().contains(columnInfo.getColumnName())) {
                continue;
            }
            for (EcpLanguage language : currentEnableLanguages) {
                String columnName =
                        RepositoryUtil.FormatMuliLangColumnName(trans2DbColumnWithAlias(columnInfo.getColumnName()), language);
                String alias = RepositoryUtil.FormatMuliLangColumnName(columnInfo.getColumnName(), language);
                // 不使用过滤，则全部添加
                if (columns!= null && columns.length() > 0) {
                    columns.append(",");
                }
                columns.append(columnName).append(" AS ").append(alias);
                if (!currentIndexMap.containsKey(alias)) {
                    currentIndexMap.put(alias, currentIndexMap.size());
                }
            }
        }
        return columns.toString();
    }

    // endregion

    // region Delete
    protected abstract String innerGetDeleteSql();

    public String getDeleteSql() {
        String innerDelSql =  innerGetDeleteSql();
        if(CAFContext.current.getDbType() == DbType.MySQL){
            if(innerDelSql.indexOf("@TableName@") != innerDelSql.lastIndexOf("@TableName@")){//包含两个@TableName@
                innerDelSql = innerGetDeleteSql().replaceFirst("@TableName@", getWrappedTableAlias());
            }
        }
        return innerDelSql.replace("@TableName@", innerGetTableName());
    }

    @Override
    public int delete(String id, DataSaveParameter par) {
        if(getLogicDeleteInfo().isEnableLogicDelete()){
            return logicDelete(id, par);
        }
        DataValidator.checkForEmptyString(id, "id");
        List<DbParameter> parameters = new ArrayList<>();
        parameters.add(buildParam("ID",getContainColumns().getPrimaryKey().getColumnType(), id));

        String sql =
                String.format("%1$s where %2$s.%3$s=?0", getDeleteSql(), getWrappedTableAlias(), getContainColumns().getPrimaryKey().getDbColumnName());
        List<FilterCondition> filter = par.getFilterCondition(getNodeCode(), id);
        if(filter != null && !filter.isEmpty()) {
            String condition = parseFilterCondition(getDB(), filter, parameters, parameters.size(),
                    false);
            sql = sql.concat(condition);
        }
        return executeSql(sql, parameters);
    }

    public int logicDelete(String id, DataSaveParameter par) {
        DataValidator.checkForEmptyString(id, "id");
        List<DbParameter> parameters = new ArrayList<>();
        parameters.add(buildParam(getLogicDeleteInfo().getLabelId(), GspDbDataType.Char, "1"));
        parameters.add(buildParam("ID", getContainColumns().getPrimaryKey().getColumnType(), id));
        String deleteSql = getModifySql() + " " + getLogicDeleteInfo().getLabelId() + " = ?0 where "
                + getContainColumns().getPrimaryKey().getDbColumnName() + "=?1 ";
        return executeSql(deleteSql, parameters);
    }

    //delete from xxx
    protected abstract String getDeleteSqlBatch();

    @Override
    public void delete(List<String> ids, DataSaveParameter par) {
        DataValidator.checkForNullReference(ids, "ids");
        if (ids.isEmpty()) {
            throw new IllegalArgumentException();
        }
        for (String item : ids) {
            FilterUtil.checkInParameterForSqlInjection(item);
        }
        executeSql(formatFiscalAndMultiLang(getDeleteSqlBatch()) + getInFilter(ids), null);
    }

    public void deleteByParent(String joinInfo, String filter, List<DbParameter> dbPars) throws SQLException {

        String idWithAlias = String.format("%1$s.%2$s", getWrappedTableAlias(), getContainColumns().getPrimaryKey().getDbColumnName());
        if(CAFContext.current.getDbType() == DbType.MySQL){
            if(getLogicDeleteInfo().isEnableLogicDelete()){
                dbPars.add(buildParam(getLogicDeleteInfo().getLabelId(), GspDbDataType.Char, "1"));
                executeSql(String.format("update %1$s set %2$s = ?%8$s WHERE %3$s IN (SELECT t_id from(SELECT %4$s as t_id FROM %5$s %6$s WHERE %7$s) t )"
                        ,  getTableName(), getLogicDeleteInfo().getLabelId(), idWithAlias, idWithAlias, getTableName(), joinInfo, filter, dbPars.size() - 1), dbPars);
            }
            else {
                executeSql(String.format("%1$s WHERE %2$s IN (SELECT t_id from(SELECT %3$s as t_id FROM %4$s %5$s WHERE %6$s) t )"
                        , getDeleteSql(), idWithAlias, idWithAlias, getTableName(), joinInfo, filter), dbPars);
            }
        }
        else{
            if(getLogicDeleteInfo().isEnableLogicDelete()){
                dbPars.add(buildParam(getLogicDeleteInfo().getLabelId(), GspDbDataType.Char, "1"));
                executeSql(String.format("update %1$s set %2$s = ?%8$s WHERE %3$s IN ( SELECT %4$s FROM %5$s %6$s WHERE %7$s )"
                        , getTableName(), getLogicDeleteInfo().getLabelId(), idWithAlias, idWithAlias, getTableName(), joinInfo, filter, dbPars.size() - 1), dbPars);
            }
            else {
                executeSql(String.format("%1$s WHERE %2$s IN ( SELECT %3$s FROM %4$s %5$s WHERE %6$s )"
                        , getDeleteSql(), idWithAlias, idWithAlias, getTableName(), joinInfo, filter), dbPars);
            }
        }
    }

    public final String buildDeleteByIDFilter() {
        return String.format("%1$s.%2$s=?0", getWrappedTableAlias(), getContainColumns().getPrimaryKey().getDbColumnName());
    }

    // endregion

    // region Insert
    protected abstract String innerGetInsertSql();

    protected String getInsertFields() {
        //region TODO 新增字段缓存起来
        if (isMultiData) {
            return getInsertFields_MultiLanguage(getContainColumns());
        }
        //TODO 后续加入生成基础be的插入字段
        return getInsertFields(getContainColumns());
        //endregion
    }

    private String getInsertFields(DbColumnInfoCollection columns){
        StringBuilder fields = new StringBuilder();
        for (DbColumnInfo containColumn : columns) {
            if (containColumn.getIsAssociateRefElement()) {
                continue;
            }
            if (fields.length() > 0)
                fields.append(",");
            String dbCol = containColumn.getDbColumnName();
            dbCol = KeyWordsManager.getColumnAlias(dbCol);

            if (containColumn.getIsMultiLang()) {
                dbCol = dbCol + "@Language@";
            }
            fields.append(dbCol);
        }
        return fields.toString();
    }

    private String getInsertFields_MultiLanguage(DbColumnInfoCollection columns) {
        StringBuilder fields = new StringBuilder();
        // 初始化
        insertMultiIndexMap = new HashMap<>();
        List<EcpLanguage> currentEnableLanguages = RepositoryUtil.getCurrentEnabledLanguages();
        for (DbColumnInfo containColumn : columns) {
            if (containColumn.getIsAssociateRefElement()) {
                continue;
            }
            // 多语单独处理
            if (containColumn.getIsMultiLang()) {
                for (EcpLanguage language : currentEnableLanguages) {
                    String alias = RepositoryUtil
                            .FormatMuliLangColumnName(containColumn.getColumnName(), language);
                    // 不使用过滤，则全部添加
                    if (fields.length() > 0) {
                        fields.append(",");
                    }
                    fields.append(alias);
                    if (insertMultiIndexMap.containsValue(alias)) {
                        throw new RuntimeException(alias + "列名重复");
                    }
                    insertMultiIndexMap.put(insertMultiIndexMap.size(), alias);
                }
                continue;
            }
            if (fields.length() > 0) {
                fields.append(",");
            }
            fields.append(containColumn.getDbColumnName());
            if (!insertMultiIndexMap.containsKey(containColumn.getColumnName())) {
                insertMultiIndexMap
                        .put(insertMultiIndexMap.size(), containColumn.getColumnName());
            }
        }
        return fields.toString();
    }

    protected String getInsertValues(RefObject<Integer> valuesCount) {
        //region TODO value缓存起来
        if (isMultiData) {
            return getInsertValues_MultiLanguage(getContainColumns(), valuesCount);
        }
        return getInsertValues(getContainColumns(),valuesCount);
        //ednregion
    }

    private String getInsertValues(DbColumnInfoCollection columns, RefObject<Integer> valuesCount){
        StringBuilder values = new StringBuilder();
        for (DbColumnInfo containColumn : columns) {
            if (containColumn.getIsAssociateRefElement()) {
                continue;
            }
            if (valuesCount.argvalue > 0)
                values.append(",");
            values.append("?");
            valuesCount.argvalue = valuesCount.argvalue + 1;
        }
        return values.toString();
    }

    private String getInsertValues_MultiLanguage(DbColumnInfoCollection columns,
                                                 RefObject<Integer> valuesCount) {
        if (insertMultiIndexMap.isEmpty()) {
            throw new RuntimeException("包含多语信息的insertSql的列信息未组织");
        }
        StringBuilder values = new StringBuilder();
        for (Map.Entry<Integer, String> entrySet : insertMultiIndexMap.entrySet()) {
            if (valuesCount.argvalue > 0) {
                values.append(",");
            }
            values.append("?");
            valuesCount.argvalue = valuesCount.argvalue + 1;
        }
        return values.toString();
    }

    public String getInsertSql() {
        return getInnerInsertSql().replace("@TableName@", innerGetTableName());
    }

    protected boolean batchInsert = false;
    private String getInnerInsertSql() {
        if ((extendContainColumns == null || extendContainColumns.getCount() < 1) && !isMultiData)
        {
            batchInsert = false;
            String insertSql = innerGetInsertSql();
            if(KeyWordsManager.getDBKeyWords(CAFContext.current.getDbType()) != null && KeyWordsManager.getDBKeyWords(CAFContext.current.getDbType()).size()>0){
                for(String keyWord : KeyWordsManager.getDBKeyWords(CAFContext.current.getDbType())){
                    insertSql = insertSql.replace(keyWord, "`"+keyWord+"`");
                }
            }
            return insertSql;
        }
        batchInsert = true;
        String insertFields = getInsertFields();
        RefObject<Integer> fieldsCount = new RefObject<>(0);
        String insertValues = getInsertValues(fieldsCount);
//        if (insertFields == null || "".equals(insertFields) || insertValues == null || insertValues.equals("")) {
//            if (extendInsertFields == null || extendInsertFields.size() == 0)
//                return getInsertSql();
//        }
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder = stringBuilder.append("INSERT INTO @TableName@  (").append(insertFields);
        if (extendContainColumns != null && extendContainColumns.getCount() > 0)
            stringBuilder.append(",").append(getInsertFields(extendContainColumns));
        stringBuilder.append(" ) Values ( ").append(insertValues);

        stringBuilder.append(getInsertValues(extendContainColumns, fieldsCount));
        stringBuilder.append(")");
        return stringBuilder.toString();
    }

    private boolean isMultiData = false;
    private Map<Integer, String> insertMultiIndexMap = new HashMap<>();
    @Override
    public int insert(IEntityData data, DataSaveParameter par, DacSaveContext batcher) throws SQLException {
        DataValidator.checkForNullReference(data, "data");
        List<String> extendFields = new ArrayList<>();
        List<String> extendValues = new ArrayList<>();

        isMultiData = (data instanceof IMultiLanguageData) && !((IMultiLanguageData) data)
                .getMultiLanguageInfos().isEmpty();
//        List<InsertFieldsInfo> extendInsertFields = new ArrayList<>();
//        for (AbstractDataAdapterExtendInfo info : getDataAdapterExtendInfos()) {
//            InsertFieldsInfo item = info.getInsertFields(data);
//            if (item == null)
//                continue;
//            extendInsertFields.add(item);
//        }

        String sql = formatFiscalAndMultiLang(getInsertSql(), batcher);
        List<DbParameter> inserParameters = getInserParameters(data);
        if(batchInsert) {
            batcher.getJDBCExecutor().addBatch(sql, inserParameters);
            return 1;
        } else {
            return executeSql(sql, inserParameters);
        }
    }

    private List<DbParameter> getInserParameters(IEntityData data) {
        ArrayList<DbParameter> dbPars = new ArrayList<DbParameter>();
        if (isMultiData) {
            buildInsertParamters_MultiLanguage(data, dbPars);
        } else {
            buildInsertParamters(data, dbPars);
        }
        if(extendContainColumns != null && extendContainColumns.getCount() > 0)
            buildEXtendInsertParamters(data, dbPars);
        return dbPars;
    }

    protected void buildInsertParamters(IEntityData entityData, ArrayList<DbParameter> dbPars) {
        for (DbColumnInfo columnInfo : getContainColumns().getBaseDict().values()) {
            if (columnInfo.getIsAssociateRefElement()) {
                continue;
            }
            Object value = this.getPersistenceValue(columnInfo.getColumnName(), entityData);
            Object transValue = value == null ? null : getPropertyChangeValue(columnInfo.getColumnName(), value);
            dbPars.add(buildParam(columnInfo.getColumnName(), columnInfo.getColumnType(), transValue));
        }
    }

    private void buildInsertParamters_MultiLanguage(IEntityData entityData,
                                                    ArrayList<DbParameter> dbPars) {
        if (insertMultiIndexMap.isEmpty()) {
            throw new RuntimeException("包含多语信息的insertSql的列信息未组织");
        }
        IMultiLanguageData multiLanguageData =
                entityData instanceof IMultiLanguageData ? (IMultiLanguageData) entityData : null;
        for (Map.Entry<Integer, String> entry : insertMultiIndexMap.entrySet()) {
            String columnName = entry.getValue();
            // 多语
            if (getMultiLanguageAlias().containsKey(columnName)) {
                MultiLangColumnInfo multiLangColumnInfo = getMultiLanguageAlias().get(columnName);
                DbColumnInfo columnInfo = getContainColumns()
                        .getItem(multiLangColumnInfo.getColumnName());
                String language = multiLangColumnInfo.getLanguageInfo().getCode();
                String columnNameWithToken = multiLangColumnInfo.getColumnName()
                        + MultiLanguageInfo.MULTILANGUAGETOKEN;
                if (multiLanguageData != null && multiLanguageData.getMultiLanguageInfos()
                        .containsKey(columnNameWithToken)) {
                    Object value = multiLanguageData.getMultiLanguageInfos()
                            .get(columnNameWithToken)
                            .getPropValueMap().get(language);
                    dbPars.add(
                            buildParam(columnName, columnInfo.getColumnType(),
                                    value));
                    continue;
                }
                if (!language.equals(CAFContext.current.getLanguage())) {
                    dbPars.add(
                            buildParam(columnName, columnInfo.getColumnType(),
                                    null));
                    continue;
                }
                // 若为当前语言，需到data中对应属性中取数,走下面的普通分支
                columnName = multiLangColumnInfo.getColumnName();
            }
            // 普通
            Object value = this.getPersistenceValue(columnName, entityData);
            Object transValue =
                    value == null ? null : getPropertyChangeValue(columnName, value);
            DbColumnInfo columnInfo = getContainColumns().getItem(columnName);
            dbPars.add(
                    buildParam(columnInfo.getColumnName(), columnInfo.getColumnType(), transValue));
        }
    }

    private void buildEXtendInsertParamters(IEntityData entityData, ArrayList<DbParameter> dbPars) {
        for (DbColumnInfo columnInfo : extendContainColumns) {
            if (columnInfo.getIsAssociateRefElement()) {
                continue;
            }

            Object transValue = null;
            if(columnInfo.getIsUdtElement()){
                for (AbstractDataAdapterExtendInfo info : getDataAdapterExtendInfos()) {
                    transValue = info.getUdtInsertValue(columnInfo.getColumnName(), columnInfo.getBelongElementLabel(), entityData);
                    if(transValue != null)
                        break;
                }
            }else{
                Object value =  entityData.getValue(columnInfo.getColumnName());
                transValue = columnInfo.getTypeTransProcesser().transType(value);
            }

            dbPars.add(buildParam(columnInfo.getColumnName(), columnInfo.getColumnType(), transValue));
        }
    }
    //endregion
    // region modify
    protected abstract String innerGetModifySql();

    private String getModifySql() {
        return innerGetModifySql().replace("@TableName@", innerGetTableName());
    }

    @Override
    public int modify(ModifyChangeDetail change, DataSaveParameter par, DacSaveContext ctx) throws SQLException {
        if ((change.getPropertyChanges() == null || change.getPropertyChanges().isEmpty()) && (
                change.getMultiLanguageInfos() == null || change.getMultiLanguageInfos().isEmpty())) {
            return 0;
        }
        List<DbParameter> parameters = new ArrayList<DbParameter>();
        RefObject<List<DbParameter>> parameters1 = new RefObject<List<DbParameter>>(parameters);
        String multiLanguageModifyValue = buildModifyValue_MultiLanguage(
                change.getMultiLanguageInfos(), parameters1);
        String modifyValue = buildModifyValue(change.getPropertyChanges(), parameters1, ctx);

        if (modifyValue.length() > 0) {
            if (multiLanguageModifyValue.length() > 0) {
                multiLanguageModifyValue = multiLanguageModifyValue.concat(", ");
            }
            multiLanguageModifyValue = multiLanguageModifyValue.concat(modifyValue);
        }
        parameters = parameters1.argvalue;
        if (multiLanguageModifyValue == null || multiLanguageModifyValue.length() == 0) {
            return 0;
        }
        int param = parameters.size();
        String execUpdateSql =
                formatFiscalAndMultiLang(getModifySql() + " " + multiLanguageModifyValue, ctx) + " where "
                        + getContainColumns().getPrimaryKey().getDbColumnName() + "=?" + (param);
        parameters.add(buildParam("ID", getContainColumns().getPrimaryKey().getColumnType(), change.getID().length(), change.getID()));

        List<FilterCondition> filter = par.getFilterCondition(getNodeCode(), change.getID());
        if(filter != null && !filter.isEmpty()) {
            String condition = parseFilterCondition(getDB(), filter, parameters, parameters.size(),
                    true);
            execUpdateSql = execUpdateSql.concat(condition);
        }

        return executeSql(execUpdateSql, parameters);
    }

    protected final String parseFilterCondition(Connection db, List<FilterCondition> filter,
                                                List<DbParameter> parameters, int paramNum, boolean ignoreAlias) {
        if (filter == null || filter.size() < 1) {
            return "";
        }
        StringBuilder conditionBuilder = new StringBuilder(" AND (");
        for (FilterCondition filterItem : filter) {
            if(StringUtils.isNullOrEmpty(filterItem.getFilterField())){
                throw new RuntimeException("存在字段为空的过滤条件，请修改!");
            }
            if(StringUtils.isNullOrEmpty(filterItem.getFilterNode())) {
                paramNum = buildFieldCondition(db, parameters, paramNum, ignoreAlias, conditionBuilder, filterItem);
            }
            else
            {
                paramNum=buildChildNodeFieldCondition(db,parameters,paramNum,ignoreAlias,conditionBuilder,filterItem);
            }
        }
        conditionBuilder.append(")");

        return conditionBuilder.toString();
    }

    private int buildFieldCondition(Connection db, List<DbParameter> parameters, int paramNum, boolean ignoreAlias, StringBuilder conditionBuilder, FilterCondition filterItem) {
        String columnName = "";
        if (filterItem.getFilterField() != null && filterItem.getFilterField().isEmpty() == false)
            columnName = trans2DbColumnWithAlias(filterItem.getFilterField(), ignoreAlias);

        GspDbDataType dataType = getDataType(filterItem.getFilterField());
        RefObject<Integer> tempRef_paramNum = new RefObject<Integer>(paramNum);
        conditionBuilder.append(FilterUtil.parseFilterCondition(filterItem, columnName, parameters, db, dataType, tempRef_paramNum, getTypeTransProcesser(filterItem.getFilterField())));
        paramNum = tempRef_paramNum.argvalue;
        return paramNum;
    }

    protected EntityDac getEntityDac()
    {throw new RuntimeException("获取EntityDac，需要在子类中复写实现。");}

    private int buildChildNodeFieldCondition(Connection db, List<DbParameter> parameters, int paramNum, boolean ignoreAlias, StringBuilder conditionBuilder, FilterCondition filterItem) {
        EntityRelationalAdaptor childAdaptor = (EntityRelationalReposAdaptor) this.getEntityDac().getChildEntityDac(filterItem.getFilterNode()).getEntityAdaptor();
        FilterCondition newCondition=new FilterCondition();
        newCondition.setlBracketCount(filterItem.getLBracketCount());
        newCondition.setRelation(filterItem.getRelation());
        newCondition.setRBracketCount(filterItem.getRBracketCount());
        newCondition.setFilterField(getPrimaryKey());
        newCondition.setCompare(ExpressCompareType.In);
        newCondition.setExpresstype(ExpressValueType.Value);

        RefObject<Integer> tempRef_paramNum = new RefObject<Integer>(paramNum);
        newCondition.setValue(childAdaptor.buildParentIdInChildQueryExpression(db,parameters,tempRef_paramNum,ignoreAlias,conditionBuilder,filterItem));
        buildFieldCondition(db,parameters,tempRef_paramNum.argvalue,ignoreAlias,conditionBuilder,newCondition);
        paramNum=tempRef_paramNum.argvalue;
        return paramNum;
    }

    private DbColumnInfo getParentIdColumn()
    {
        for (DbColumnInfo dbColumnInfo:getContainColumns())
        {
            if(dbColumnInfo.getIsParentId())
                return dbColumnInfo;
        }
        throw new RuntimeException("找不到ParentID列");
    }

    private String buildParentIdInChildQueryExpression(Connection db, List<DbParameter> parameters, RefObject<Integer> tempRef_paramNum, boolean ignoreAlias, StringBuilder conditionBuilder, FilterCondition filterItem) {
        String parentIdColumn = getParentIdColumn().getColumnName();

        StringBuilder stringBuilder=new StringBuilder();
        stringBuilder.append(" SELECT ").append(parentIdColumn).append(" from ").append(getTableName()).append(" where ");
        filterItem.setRelation(ExpressRelationType.Empty);
        filterItem.setlBracketCount(0);
        filterItem.setRBracketCount(0);
        tempRef_paramNum .argvalue=buildFieldCondition(db,parameters,tempRef_paramNum.argvalue,ignoreAlias,stringBuilder,filterItem);
        return stringBuilder.toString();
    }

    private String buildModifyValue(Map<String, Object> propertyChanges, RefObject<List<DbParameter>> parameters, DacSaveContext ctx) {
        StringBuilder modifyValue = new StringBuilder();
        int paramNum = parameters.argvalue.size();
        for (Map.Entry<String, Object> propertyChange : propertyChanges.entrySet()) {
            if (!(propertyChange.getValue() instanceof ValueObjModifyChangeDetail)) {

                //TODO 临时判断，之后讨论虚拟字段变更集传递，后去掉
                if (!getContainColumns().contains(propertyChange.getKey())) {
                    continue;
                }

                String dbCol = trans2DbColumn(propertyChange.getKey());
                // 多语变更集中已经包含，则普通变更集不再包含
                if (parameters.argvalue.size() != 0) {
                    AtomicReference<Boolean> alreadyHas = new AtomicReference<>(false);
                    parameters.argvalue.forEach(para -> {
                        if (
                                para.getParamName()
                                        .equals(RepositoryUtil.FormatMuliLang(dbCol, ctx.getFieldSuffix()))) {
                            alreadyHas.set(true);
                            return;
                        }
                    });
                    if (alreadyHas.get()) {
                        continue;
                    }
                }

                if (modifyValue.length() > 0) {
                    modifyValue.append(" , ");
                }
                modifyValue.append(KeyWordsManager.getColumnAlias(dbCol) + " = ?" + (paramNum++));

                Object value = getContainColumns().getItem(propertyChange.getKey()).getTypeTransProcesser().transType(propertyChange.getValue());
                parameters.argvalue.add(buildParam(propertyChange.getKey(), getDataType(propertyChange.getKey()), getPropertyChangeValue(propertyChange.getKey(), value)));
            } else {
                paramNum = dealUdtModifyValue(propertyChange.getKey(), propertyChange.getValue(), paramNum, modifyValue, parameters.argvalue);
            }
        }

        for (AbstractDataAdapterExtendInfo info : getDataAdapterExtendInfos()) {
            info.buildModifyValues(modifyValue, propertyChanges, parameters);
        }
        return modifyValue.toString();
    }
    private int dealUdtModifyValue(String propertyName, Object propertyValue, int paramNum, StringBuilder modifyValue, List<DbParameter> parameters) {
        ArrayList<DbColumnInfo> columns = getUdtColumnInfos(propertyName);
        if (columns.isEmpty() == false && paramNum > 0 && modifyValue.length() > 0) {
            modifyValue.append(" , ");
        }
        for (int i = 0; i < columns.size(); i++) {
            DbColumnInfo column = columns.get(i);
            if (column.getIsAssociateRefElement()) {
                continue;
            }
            if (i > 0) {
                modifyValue.append(" , ");
            }
            String dbCol = column.getDbColumnName();
            if (column.getIsMultiLang()) {
                dbCol = dbCol + "@Language@";
            }
            modifyValue.append(dbCol + " = ?" + (paramNum++));
            parameters.add(buildParam(column.getColumnName(), column.getColumnType(), getPropertyChangeValue(column.getColumnName(), propertyValue)));
        }

        return paramNum;
    }

    private String buildModifyValue_MultiLanguage(Map<String, MultiLanguageInfo> infos,
                                                  RefObject<List<DbParameter>> parameters) {
        if (parameters.argvalue == null) {
            parameters.argvalue = new ArrayList<DbParameter>();
        }
        StringBuilder modifyValue = new StringBuilder();
        int paramNum = parameters.argvalue.size();
        for (Map.Entry<String, MultiLanguageInfo> entrySet : infos.entrySet()) {
            String propName = entrySet.getKey().split(MultiLanguageInfo.MULTILANGUAGETOKEN)[0];
            if (!getContainColumns().contains(propName)) {
                continue;
            }

            for (Map.Entry<String, Object> item : entrySet.getValue().getPropValueMap()
                    .entrySet()) {
                String languageCode = item.getKey();
                String dbCol = trans2DbColumn(propName);
                String columnName = RepositoryUtil
                        .FormatMuliLangColumnName(dbCol, RepositoryUtil.getLanguage(languageCode));

                if (modifyValue.length() > 0) {
                    modifyValue.append(" , ");
                }
                modifyValue.append(columnName + " = ?" + (paramNum++));

                parameters.argvalue.add(
                        buildParam(columnName, getDataType(propName), item.getValue())
                );
            }
        }
        return modifyValue.toString();
    }

    private ArrayList<DbColumnInfo> getUdtColumnInfos(String belongElementLabel) {
        ArrayList<DbColumnInfo> infos = new ArrayList<DbColumnInfo>();
        for (DbColumnInfo containColumn : getContainColumns()) {
            if (belongElementLabel.equals(containColumn.getBelongElementLabel())) {
                infos.add(containColumn);
            }
        }

        return infos;
    }

    protected abstract Object getPropertyChangeValue(String key, Object value);

    // endregion


    protected GspDbDataType getDataType(String key) {
        DbColumnInfo columnInfo = getColumnInfoByColumnNameName(key);
        if (columnInfo == null)
            throw new RuntimeException("找不到属性" + key + "对应的列信息");
        return columnInfo.getColumnType();

    }

    private DbColumnInfo getColumnInfoByColumnNameName(String columnName) {
        for (DbColumnInfo columnInfo : getContainColumns()) {
            if (columnInfo.getColumnName().toLowerCase().equals(columnName.toLowerCase()))
                return columnInfo;
        }
        for (AbstractDataAdapterExtendInfo extendInfo : getDataAdapterExtendInfos()) {
            DbColumnInfo columnInfo = extendInfo.tryGetColumnInfoByPropertyName(columnName);
            if (columnInfo != null)
                return columnInfo;
        }
        if (this.extendContainColumns != null && this.extendContainColumns.getCount() > 0) {
            for (DbColumnInfo columnInfo : this.extendContainColumns) {
                if (columnInfo.getColumnName().toLowerCase().equals(columnName.toLowerCase())) {
                    return columnInfo;
                }
            }
        }
        throw new RuntimeException("找不到属性" + columnName + "对应的列信息");
    }

    protected String trans2DbColumn(String key) {
        for (DbColumnInfo info : getContainColumns()) {
            if (info.getColumnName().equals(key)) {
                return info.getRealColumnName();
            }
        }
        throw new RuntimeException("未找到字段:" + key);
    }

    private String trans2DbColumnWithAlias(String filedName) {
        return trans2DbColumnWithAlias(filedName, false);
    }
    protected String trans2DbColumnWithAlias(String filedName,  boolean ignoreAlias) {
        filedName=DatabaseUtil.getColumnName(filedName);
        if (!getContainColumns().contains(filedName) && (extendContainColumns == null || !extendContainColumns.contains(filedName))) {
            StringBuilder sb = new StringBuilder();
            sb.append("当前BE(v1):"+getWrappedTableAlias() + " configId:" + getConfigId());
            sb.append("包含列信息{{");
            for(DbColumnInfo dbColumnInfo: getContainColumns()){
                sb.append(dbColumnInfo.getColumnName() + ",");
            }
            sb.append("}}");
            logger.error("未找到字段" + filedName + "，请确认字段名称是否输入正确，或关联引用字段是否已经获取");
            logger.error(sb.toString());
            //再换种方式比较一次？
            for (DbColumnInfo columnInfo : getContainColumns()) {
                if (columnInfo.getColumnName().toLowerCase().equals(filedName.toLowerCase())) {
                    logger.error("找到字段" + filedName + "");
                }
            }
            throw new RuntimeException("未找到字段" + filedName + "，请确认字段名称是否输入正确，或关联引用字段是否已经获取");
        }
        DbColumnInfo columnInfo = getContainColumns().getItem(filedName);
        if (columnInfo == null)
            columnInfo = extendContainColumns.getItem(filedName);
        if (columnInfo.getIsAssociateRefElement()) {
            return getAssociateDbColumnName(columnInfo);
        }
        //return assColumns.ContainsKey(filedName) ? assColumns[filedName] : throw new Exception("Error");
        String dbName = ignoreAlias ? columnInfo.getDbColumnName() : getWrappedTableAlias() + "." + KeyWordsManager.getColumnAlias(columnInfo.getDbColumnName());
        if (columnInfo.getIsMultiLang()) {
            dbName = dbName + "@Language@";
        }
        return dbName;
    }

    private String getAssociateDbColumnName(DbColumnInfo columnInfo) {
        if (columnInfo.getDbColumnName() == null || columnInfo.getDbColumnName().length() == 0) {
            throw new RuntimeException("尚未获取关联引用字段数据库列名称，请先获取引用字段");
        }
        return columnInfo.getDbColumnName();
    }

    protected abstract String getGetDataByIdsSql();

    @Override
    public List<IEntityData> getDataByIDs(List<String> dataIds) {
        return getDataByIds(dataIds,null);
    }

    public  List<IEntityData>  getDataByIds(List<String> dataIds,EntityFilter nodeFilter)
    {
        initQueryTableName();
        for (String item : dataIds) {
            FilterUtil.checkInParameterForSqlInjection(item);
        }
        String tableName =getQueryTableNameWithAuthority(null,nodeFilter);
        String fields =getQueryFields(nodeFilter);
        String sql = String.format(getGetDataByIdsSql(), fields, tableName, "%1$s");

        return getDatasBatch(formatFiscalAndMultiLang(sql), dataIds);
    }

    protected abstract String getGetDataByIdSql();

    @Override
    public IEntityData getDataByID(String dataId) {
        return getDataByID(dataId,null);
    }

    public IEntityData getDataByID(String dataId, EntityFilter filter) {
        RetrieveFilter rtFilter = new RetrieveFilter();
        rtFilter.getNodeFilters().put(getNodeCode(), filter);
        return this.getDataByIDWithPara(dataId,new AdaptorRetrieveParam(rtFilter));
    }


    public IEntityData getDataByIDWithPara(String dataId, AdaptorRetrieveParam adaptorRetrieveParam) {
        EntityFilter filter = adaptorRetrieveParam.getEntityfilter(getNodeCode());
        if(  filter!=null&&filter.getFieldsFilter()!=null&&filter.getFieldsFilter().getFilterFields()!=null) {
            if (getVersionControlPropName() != null && getVersionControlPropName().equals("") == false &&
                    filter.getFieldsFilter().getFilterFields().contains(getVersionControlPropName()) == false)
                filter.getFieldsFilter().getFilterFields().add(getVersionControlPropName());
            if(getPrimaryKey()!=null&&getPrimaryKey().equals("")==false&&filter.getFieldsFilter().getFilterFields().contains(getPrimaryKey()))
                filter.getFieldsFilter().getFilterFields().add(getPrimaryKey());
        }

        initQueryTableName();
        String tableName = getQueryTableNameWithAuthority(null, adaptorRetrieveParam!=null? adaptorRetrieveParam.getEntityfilter(getNodeCode()): null);
        String fields = getQueryFields(adaptorRetrieveParam);
        // 赋值全局变量，当前需查询的所有字段，包含多语列
        queryFields = fields;
        String sql = String.format(getGetDataByIdSql(), fields, tableName, "?0 ");

        try {
            List<DbParameter> list = new ArrayList<DbParameter>();
            list.add(buildParam("ID", getContainColumns().getPrimaryKey().getColumnType(), dataId));
            return innerGetData(formatMultiLang(sql), list, adaptorRetrieveParam);
        } catch (RuntimeException ex) {
            throw new RuntimeException(buildMessage(ex.getMessage()),ex);
        }
    }

    public final void generateTable() {
        //getDboService().deployTempTable(getDboID());
    }

    public TempTableContext createTempTable()
    {
        return getDboService().creatTempTables(getDboID());
    }

    public final void dropTable() {
//		Java版临时注释
//		ServiceManager.<IDatabaseObjectDeployService>GetService().DropTempTable(getDboID());
    }

    public  void dropTempTable(TempTableContext tempTableContext)
    {
        getDboService().dropTempTable(tempTableContext,getDboID());
    }

    private AdapterUQChecker getAdapterUQChecker(boolean throwEx) {
        return new AdapterUQChecker(this, throwEx);
    }

    /**
     * 每一个UQConstraintMediate构造一个SQL
     *
     * @param mediates
     */
    public final void checkUniqueness(ArrayList<UQConstraintMediate> mediates) {
        checkUniqueness(mediates, true);
    }

    public final void checkUniqueness(ArrayList<UQConstraintMediate> mediates, boolean throwEx) {
        getAdapterUQChecker(throwEx).checkUniqueness(mediates);
    }

    private IEntityData innerGetData(String sql, List<DbParameter> parameters, AdaptorRetrieveParam param) {
        ArrayList<IEntityData> datas = getDatas(sql, parameters, param);
        return datas.stream().findFirst().orElse(null);
    }

    public abstract String getParentJoin();

    protected final void addColumn(String columnName, String dbColumnName, GspDbDataType columnType, int length, int precision, Object defaultValue
            , ITypeTransProcesser typeTransProcesser, boolean isPrimaryKey, boolean isAssociateRefElement, boolean isMultiLang, boolean isUdt
            , boolean isAssociation, boolean isEnum, String belongElementLabel, boolean isParentId) {
        DbColumnInfo tempVar = new DbColumnInfo();
        tempVar.setColumnName(columnName);
        tempVar.setDbColumnName(isAssociateRefElement ? "" : dbColumnName);
        tempVar.setColumnType(columnType);
        tempVar.setLength(length);
        tempVar.setPrecision(precision);
        tempVar.setDefaultValue(defaultValue);
        tempVar.setIsPrimaryKey(isPrimaryKey);
        tempVar.setIsAssociateRefElement(isAssociateRefElement);
        tempVar.setIsMultiLang(isMultiLang);
        tempVar.setIsParentId(isParentId);
        tempVar.setIsUdtElement(isUdt);
        tempVar.setIsAssociation(isAssociation);
        tempVar.setIsEnum(isEnum);
        tempVar.setBelongElementLabel(belongElementLabel);
        tempVar.setTypeTransProcesser(typeTransProcesser);
        DbColumnInfo columnInfo = tempVar;
        getContainColumns().add(columnInfo);
    }

    protected boolean getHasMultiLangCol() {
        if (hasMultiLangCol == null) {
            for (DbColumnInfo col : getContainColumns()) {
                if (col.getIsMultiLang()) {
                    hasMultiLangCol = true;
                    break;
                }
            }
            return hasMultiLangCol;
        }
        return false;
    }

    private Query buildQueryManager(String sqlText, List<DbParameter> parameters) {
        DataValidator.checkForEmptyString(sqlText, "sqlText");
        Query query = entityManager.createNativeQuery(sqlText);
        if (parameters != null) {
            for (int i = 0; i < parameters.size(); i++) {
                DbParameter param = parameters.get(i);
                switch(param.getDataType()){
                    case VarChar:
                    case NVarChar:
                    case NChar:
                    case Blob:
                    case Boolean:
                        query.setParameter(i,param.getValue());
                        break;
                    case Clob:
                        //TODO 后续测试DM数据库是否合适
                        query.setParameter(i, new TypedParameterValue(StandardBasicTypes.TEXT, param.getValue()));
                        break;
                    case Int:
                        if(param.getValue()!=null && param.getValue() instanceof String){
                            Object value=Integer.parseInt(param.getValue().toString());
                            query.setParameter(i,new TypedParameterValue(StandardBasicTypes.INTEGER, value));

                        }else {
                            query.setParameter(i,new TypedParameterValue(StandardBasicTypes.INTEGER, param.getValue()));
                        }
                        break;
                    case Decimal:
                        query.setParameter(i,new TypedParameterValue(StandardBasicTypes.BIG_DECIMAL, param.getValue()));
                        break;
                    case Char:
                        if(param.getValue()==null){
                            query.setParameter(i,new TypedParameterValue(StandardBasicTypes.STRING, param.getValue()));

                        }else {
                            query.setParameter(i,param.getValue()) ;
                        }
                        break;
                    case NClob:
                        if(CAFContext.current.getDbType()==DbType.Oracle) {
                            if(CAFContext.current.getDbType() == DbType.Oscar){
                                query.setParameter(i, new TypedParameterValue(StandardBasicTypes.TEXT, param.getValue()));
                            }
                            else {
                                query.setParameter(i, new TypedParameterValue(StandardBasicTypes.NTEXT, param.getValue()));
                            }

                        }else{
                            query.setParameter(i, new TypedParameterValue(StandardBasicTypes.TEXT, param.getValue()));
                        }
                        break;
                    case DateTime:
                        if(CAFContext.current.getDbType() == DbType.Oscar) {
                            if(param.getValue() == null){
                                query.setParameter(i, (Date) param.getValue(), TemporalType.DATE);
                            }
                            else {
                                query.setParameter(i, Date.from(((Date)param.getValue()).toInstant()), TemporalType.DATE);
                            }
                            query.setParameter(i, (Date) param.getValue(), TemporalType.DATE);
                        }
                        else {
                            query.setParameter(i, (Date) param.getValue(), TemporalType.DATE);
                        }
                        break;
                    case Date:
                        if(param.getValue() == null){
                            query.setParameter(i, (Date) param.getValue(), TemporalType.DATE);
                            break;
                        }

                        java.sql.Date date = new  java.sql.Date(((Date) param.getValue()).getTime());
                        date = java.sql.Date.valueOf(date.toString());
                        query.setParameter(i, date, TemporalType.DATE);
                        break;
                    default:
                        throw new RuntimeException("未知的数据类型，请确认参数的类型。");
                }
////				query.setParameter(i, param.getValue());
//                if (param.getDataType() == GspDbDataType.DateTime) {
//                    query.setParameter(i, (Date) param.getValue(), TemporalType.DATE);
//                } else if(param.getDataType()==GspDbDataType.Int){
//                    query.setParameter(i, new TypedParameterValue(StandardBasicTypes.INTEGER, param.getValue()));
//                }else if(param.getDataType()==GspDbDataType.Decimal){
//                    query.setParameter(i, new TypedParameterValue(StandardBasicTypes.BIG_DECIMAL, param.getValue()));
//                }else if(param.getDataType()==GspDbDataType.Char){
//                    if(param.getValue()==null) {
//                        query.setParameter(i, new TypedParameterValue(StandardBasicTypes.BOOLEAN, param.getValue()));
//                    }
//                    else{
//                        query.setParameter(i,param.getValue());
//                    }
//                }else if(param.getDataType()== GspDbDataType.NClob) {
//                    query.setParameter(i, new TypedParameterValue(StandardBasicTypes.NCLOB, param.getValue()));
//                }else{
//                    query.setParameter(i, param.getValue());
//
//                }
//
            }
        }
        return query;
    }

    @Transactional
    protected int executeSql(String sqlText, List<DbParameter> parameters) {

        Query query = buildQueryManager(sqlText, parameters);
        return query.executeUpdate();
    }

    protected Object executeScelar(String sqlText, List<DbParameter> parameters) {
        DataValidator.checkForEmptyString(sqlText, "sqlText");

        Query query = buildQueryManager(sqlText, parameters);
        List<Object[]> resultSet = query.getResultList();
        return resultSet.get(0)[0];
    }

    public final DbParameter buildParam(String paramName, GspDbDataType dataType, int size, Object paramValue) {
        return new DbParameter(paramName, dataType, paramValue);
    }

    public final DbParameter buildParam(String paramName, GspDbDataType dataType, Object paramValue) {
        return FilterUtil.buildParam(paramName, dataType, paramValue);
    }

    protected final String formatFiscalAndMultiLang(String sql) {
        //if (EnableFiscal)
        //    sql = FormatFiscal(sql);
        //if (HasMultiLangCol)
        sql = formatMultiLang(sql);
        return sql;
    }

    protected final String formatFiscalAndMultiLang(String sql, DacSaveContext batcher) {
        sql = RepositoryUtil.FormatMuliLang(sql, batcher.getFieldSuffix());
        return sql;
    }

    //private String FormatFiscal(String sql)
    //{
    //    return RepositoryUtil.FormatFiscal(sql, Convert.ToString(DboID));
    //}

    private String formatMultiLang(String sql) {
        return RepositoryUtil.FormatMuliLang(sql);
    }

    private String getUniquenessSQL(UQConstraintMediate mediate, ArrayList<DbParameter> parameters) {
        if (mediate.getParametersInfo().isEmpty()) {
            return null;
        }
        int index = 0;
        StringBuilder sql = new StringBuilder();
        sql.append(String.format("SELECT COUNT(1) FROM %1$s ", innerGetTableName()));
        RefObject<Integer> tempRef_index = new RefObject<Integer>(index);
        sql.append(String.format(" WHERE %1$s", getUQSql(mediate, tempRef_index, parameters)));
        index = tempRef_index.argvalue;
        return sql.toString();
    }

    private String getUQSql(UQConstraintMediate mediate, RefObject<Integer> index, ArrayList<DbParameter> parameters) {
        StringBuilder sql = new StringBuilder();

        HashMap<String, HashMap<String, Object>> info = mediate.getParametersInfo();
        ArrayList<String> exceptIDs = new ArrayList<String>();
        exceptIDs.addAll(mediate.getExceptDeleteIds());
        exceptIDs.addAll(mediate.getExceptModifyIds());

        StringBuilder id = new StringBuilder();
        for (String item : exceptIDs) {
            id.append("'" + item + "'" + ",");
        }

        StringBuilder or = new StringBuilder();
        int count1 = info.keySet().size() - 1;
        int j = 0;
        for (String item : info.keySet()) {
            or.append("(");
            HashMap<String, Object> fieldsInfo = info.get(item);
            int count2 = fieldsInfo.keySet().size() - 1;
            int i = 0;
            for (Map.Entry<String, Object> field : fieldsInfo.entrySet()) {
                String column = trans2DbColumn(field.getKey());
                Object value = null;
                if (false)
//				if (field.getValue() instanceof IUdtData)
                {
                    value = field.getValue();
                } else {
                    value = getContainColumns().getItem(field.getKey()).getTypeTransProcesser().transType(field.getValue());
                }
                try {
                    Object dbValue = getPropertyChangeValue(field.getKey(), value);
                    parameters.add(buildParam(field.getKey() + "_" + (new Integer(j)).toString(), getDataType(field.getKey()), dbValue));

                    if (dbValue == null) {
                        or.append(String.format("%1$s=? or %1$s is null", column));
                    } else {
                        or.append(String.format("%1$s=?", column));
//						or.append($" {column}={" {" + index++ + "}"} ");
                    }

                    //or.Append(column + "=" + "'" + value + "' ");
                    if (i != count2) {
                        or.append(" AND ");
                    }
                    i++;
                } catch (Exception e) {
                    System.out.println(field.getKey());
                    if (value == null) {
                        System.out.println("Value is Null");
                    }
                    throw e;
                }

            }
            or.append(")");
            if (j != count1) {
                or.append(" OR ");
            }
            j++;
        }
        if (id.length() != 0) {
            sql.append(String.format("(%1$s) AND ID NOT IN (%2$s)", or.toString(), id.toString().substring(0, id.toString().length() - 1)));
        } else {
            sql.append(String.format("(%1$s)", or.toString()));
        }


        return sql.toString();
    }


    protected abstract String getJoinTableName();

    @Override
    public String getTableNameByColumns(HashMap<String, String> columns, String keyColumnName, RefObject<String> keyDbColumnName, ArrayList<String> tableAlias) {
        //跟之前一致。
        ArrayList<String> keys1 = new ArrayList<>();
        for (String key : columns.keySet()
        ) {
            keys1.add(key);
        }
        ArrayList<AssociationInfo> associations = getAssociationInfos(keys1);
        String tableName = getTableNamesWithAssociationInfo(associations, tableAlias);
        keyDbColumnName.argvalue = trans2DbColumnWithAlias(keyColumnName);

        String[] keys = keys1.toArray(new String[]{});
        for (int i = 0; i < keys.length; i++) {
            columns.put(keys[i], trans2DbColumnWithAlias(keys[i]));
        }
        return tableName;
    }

    @Override
    public String getTableNameByRefColumns(HashMap<String, RefColumnInfo> columns, String keyColumnName, RefObject<String> keyDbColumnName, ArrayList<String> tableAlias) {
        //跟之前一致。
        ArrayList<AssociationInfo> associations = getAssociationInfos(columns);
        String tableName = getTableNamesWithAssociationInfo(associations, tableAlias);
        keyDbColumnName.argvalue = trans2DbColumnWithAlias(keyColumnName);

        List<String> keys = new ArrayList<String>();
        for (String key : columns.keySet()) {
            keys.add(key);
        }
        for (int i = 0; i < keys.size(); i++) {
            RefColumnInfo tempVar = new RefColumnInfo();
            tempVar.setColumnName(trans2DbColumnWithAlias(keys.get(i)));
            tempVar.setTransProcesser(getContainColumns().getItem(keys.get(i)).getTypeTransProcesser());
            tempVar.setColumnType(getContainColumns().getItem(keys.get(i)).getColumnType());
            columns.put(keys.get(i), tempVar);
        }
        return tableName;
        //return tableName;
    }


    ///#region GetJoinTable
    public final String getJoinTableName(ArrayList<String> columns, ArrayList<String> tableAlias, String currentAlias) {
        HashMap<AssociationInfo, ArrayList<String>> assos = getAssoInfos(columns);

        StringBuilder queryTables = new StringBuilder();
        for (Map.Entry<AssociationInfo, ArrayList<String>> assoItem : assos.entrySet()) {
            AssociationInfo associationInfo = assoItem.getKey();
            ArrayList<String> currentColumns = assoItem.getValue();
            HashMap<String, RefColumnInfo> associationColumns = new HashMap<String, RefColumnInfo>();
            for (String item : currentColumns) {
                associationColumns.put(associationInfo.getRefColumns().get(item), new RefColumnInfo());
            }

            if (getConfigId().equals(associationInfo.getConfigId())) {
                queryTables.append(getCurrentAssoTableName(associationInfo, tableAlias, associationColumns));
                continue;
            }
            String targetDbColumnName = "";
            associationInfo.getRefRepository().initParams(getPars());
            associationInfo.getRefRepository().initRepoVariables(getVars());
            RefObject<String> tempRef_targetDbColumnName = new RefObject<String>(targetDbColumnName);
            String tableName = associationInfo.getRefRepository().getTableNameByRefColumns(associationInfo.getNodeCode(), associationColumns, associationInfo.getTargetColumn(), tempRef_targetDbColumnName, tableAlias);
            targetDbColumnName = tempRef_targetDbColumnName.argvalue;

            initAssociateColumnInfo(associationInfo, associationColumns);

            String sourceColumnName = currentAlias + "." + trans2DbColumn(associationInfo.getSourceColumn());
            queryTables.append(String.format(getJoinTableName(), tableName, sourceColumnName, targetDbColumnName));
        }

        return queryTables.toString();

    }

    protected final HashMap<AssociationInfo, ArrayList<String>> getAssoInfos(ArrayList<String> columns) {
        HashMap<AssociationInfo, ArrayList<String>> assos = new HashMap<AssociationInfo, ArrayList<String>>();
        for (String column : columns) {
            AssociationInfo info = findInAssociationInfos(column);
            if (!assos.containsKey(info)) {
                assos.put(info, new ArrayList<String>());
            }
            assos.get(info).add(column);
        }

        return assos;
    }
    public CefEntityResInfoImpl getEntityResInfo() {
        return null;
    }
    private ArrayList<AssociationInfo> getAssociationInfos(HashMap<String, RefColumnInfo> columnInfos) {
        ArrayList<String> columns = new ArrayList<String>();
        for (String item :
                columnInfos.keySet()) {
            columns.add(item);
        }
        ArrayList<AssociationInfo> associations = new ArrayList<AssociationInfo>();
        for (String columnItem : columns) {
            if (!getContainColumns().contains(columnItem) || getContainColumns().getItem(columnItem).getIsAssociateRefElement()) {
                AssociationInfo assoInfo = findInAssociationInfos(columnItem);
                if (assoInfo == null && getEntityResInfo()!=null) {
                    //如果是多值多列udt
                    DataTypePropertyInfo dataTypePropertyInfo = getEntityResInfo().getEntityTypeInfo().getPropertyInfos().get(columnItem);
                    Object udtPropertyInfo = null;
                    if(dataTypePropertyInfo != null){
                        udtPropertyInfo = getEntityResInfo().getEntityTypeInfo().getPropertyInfos().get(columnItem).getObjectInfo();
                    }

                    if (udtPropertyInfo != null && udtPropertyInfo instanceof ComplexUdtPropertyInfo) {
                        if (columnInfos.containsKey(columnItem)) {
                            columnInfos.remove(columnItem);
                        }
                        for (Map.Entry<String, DataTypePropertyInfo> entry : ((ComplexUdtPropertyInfo) udtPropertyInfo).getPropertyInfos().entrySet()) {
                            if (!columnInfos.containsKey(entry.getKey())) {
                                columnInfos.put(entry.getKey(), new RefColumnInfo());
                            }
                        }
                    } else {
                        throw new RuntimeException("找不到字段" + columnItem);
                    }
                } else {
                    if (!associations.contains(assoInfo)) {
                        associations.add(assoInfo);
                    }
                }
            }

            if (getContainColumns().contains(columnItem) && getContainColumns().getItem(columnItem).getIsAssociation()) {
                AssociationInfo assoInfo = getAssociation(columnItem);
                if (!associations.contains(assoInfo)) {
                    associations.add(assoInfo);
                    for (String refColumn : assoInfo.getRefColumns().keySet()) {
                        if (!columnInfos.containsKey(refColumn)) {
                            columnInfos.put(refColumn, new RefColumnInfo());
                        }
                    }
                }

            }
        }
        return associations;
    }

    private ArrayList<AssociationInfo> getAssociationInfos(ArrayList<String> columns) {
        ArrayList<AssociationInfo> associations = new ArrayList<AssociationInfo>();
        for (String columnItem : columns) {
            if (!getContainColumns().contains(columnItem) || getContainColumns().getItem(columnItem).getIsAssociateRefElement()) {
                AssociationInfo assoInfo = findInAssociationInfos(columnItem);
                if (associations.contains(assoInfo)) {
                    associations.add(assoInfo);
                }
            }

            if (getContainColumns().contains(columnItem) && getContainColumns().getItem(columnItem).getIsAssociation()) {
                AssociationInfo assoInfo = getAssociation(columnItem);
                if (associations.contains(assoInfo)) {
                    associations.add(assoInfo);
                }
            }
        }
        return associations;
    }

    private AssociationInfo findInAssociationInfos(String columnName) {
        for (AssociationInfo associationInfo : getAssociationInfos()) {
            if (associationInfo.getRefColumns().containsKey(columnName)) {
                return associationInfo;
            }
        }
        return null;
//        throw new RuntimeException("找不到字段" + columnName);
    }

    private String getTableNamesWithAssociationInfo(ArrayList<AssociationInfo> associations, ArrayList<String> tableAlias) {
        if (tableAlias == null) {
            tableAlias = new ArrayList<String>();
            addTableAlias(tableAlias);
        } else {
            setTableAlias(getTableAlias4Association(tableAlias));
        }
        if (associations == null || associations.size() < 1) {
//            tableAlias.add(getTableAlias());
            return getTableName();
        }

        return buildTableNamesWithAssociationInfo(associations, tableAlias, getTableName());
    }

    private String buildTableNamesWithAssociationInfo(ArrayList<AssociationInfo> associations, ArrayList<String> tableAlias, String baseTableName) {
        StringBuilder queryTables = new StringBuilder().append(baseTableName);
        for (AssociationInfo associationInfo : associations) {
            HashMap<String, RefColumnInfo> associationColumns = new HashMap<String, RefColumnInfo>();
            for (Map.Entry<String, String> item :
                    associationInfo.getRefColumns().entrySet()) {
                associationColumns.put(item.getValue(), new RefColumnInfo());
            }

            if (getConfigId().equals(associationInfo.getConfigId()) && getNodeCode() == associationInfo.getNodeCode()) {
                queryTables.append(getCurrentAssoTableName(associationInfo, tableAlias, associationColumns));
                continue;
            }
            String targetDbColumnName = "";
            associationInfo.getRefRepository().initParams(getPars());
            RefObject<String> tempRef_targetDbColumnName = new RefObject<String>(targetDbColumnName);
            String tableName = associationInfo.getRefRepository().getTableNameByRefColumns(associationInfo.getNodeCode(), associationColumns, associationInfo.getTargetColumn(), tempRef_targetDbColumnName, tableAlias);
            targetDbColumnName = tempRef_targetDbColumnName.argvalue;

            initAssociateColumnInfo(associationInfo, associationColumns);

            String sourceColumnName = trans2DbColumnWithAlias(associationInfo.getSourceColumn());
            queryTables.append(String.format(getJoinTableName(), tableName, sourceColumnName, targetDbColumnName));
            buildAssoCondi(queryTables, associationInfo, targetDbColumnName, tableName);
        }

        return queryTables.toString();
    }

    private void buildAssoCondi(StringBuilder queryTables, AssociationInfo associationInfo, String targetDbColumnName, String tableName){
        //todo 这个地方别名处理待验证,字段如果与数据库不一致？ 前端直接用数据库的？
        if(targetDbColumnName.indexOf(".") < 0){
            return;
        }
        String targetAlias = targetDbColumnName.substring(0, targetDbColumnName.indexOf("."));
        if(associationInfo.getAssoConditions() != null && associationInfo.getAssoConditions().size() >0){
            for(AssoCondition assoCondition: associationInfo.getAssoConditions()){
                if(StringUtils.isEmpty(assoCondition.getValue())){
                    queryTables.append(" and " + getAssoAlias(assoCondition.getLeftNodeCode(), tableName) + "." + assoCondition.getLeftField());
                    queryTables.append(StringUtils.isEmpty(assoCondition.getOperator()) ? "=" : assoCondition.getOperator());
                    queryTables.append(getAssoAlias(assoCondition.getRightNodeCode(), targetAlias) + "." + assoCondition.getRightField());
                }
                else {
                    queryTables.append(" and " + getAssoAlias(assoCondition.getLeftNodeCode(), targetAlias) + "." + assoCondition.getLeftField());
                    queryTables.append(StringUtils.isEmpty(assoCondition.getOperator()) ? "=" : assoCondition.getOperator());
                    //todo wangmj 先按照字符串处理，后续结合类型处理
                    queryTables.append(" '" + assoCondition.getValue()+"' " );
                }
            }
        }

        if(associationInfo.getWhere() !=null && associationInfo.getWhere().length() >0){
            String where = associationInfo.getWhere();
            where = trimLeft(where);
            String[] array = where.split("=");
            //有可能是 code = 'test' 不带别名
            if(array.length > 1 && array[1].indexOf(".") < 0 && array[0].indexOf(".") > 0){//改造第一个
                //函数暂时不考虑 AND upper(GSPWFCOMMENT.Action) = 'PASS'
                if(!(array[0].contains("(") && array[0].contains(")"))){
                    int index = where.split("=")[0].indexOf(".");
                    where = targetAlias + array[0].substring(index) + "=" + array[1];
                }
            }
            if(where.toLowerCase().startsWith("and")){
                queryTables.append(" " + where);
            }
            else {
                queryTables.append(" and " + where);
            }
        }
    }
    /**
     * 去左空格
     * @param str
     * @return
     */
    public String trimLeft(String str) {
        if (str == null || str.equals("")) {
            return str;
        } else {
            return str.replaceAll("^[　 ]+", "");
        }
    }
    private String getAssoAlias(String nodeCode, String targetTableName){
        if(getTableAlias().equals(nodeCode))
            return getTableAlias();
        return targetTableName;
    }

    private String getCurrentAssoTableName(AssociationInfo associationInfo, ArrayList<String> tableAlias, HashMap<String, RefColumnInfo> associationColumns) {
        String currnetAlias = getTableAlias4Association(tableAlias);
        ArrayList<AssociationInfo> associations = getAssociationInfos(associationColumns);
        String tableName = buildTableNamesWithAssociationInfo(associations, tableAlias, innerGetTableName() + " " + currnetAlias);
        String keyDbColumnName = currnetAlias + "." + trans2DbColumn(associationInfo.getTargetColumn());

        ArrayList<String> keys = new ArrayList<String>();
        for (String key :
                associationColumns.keySet()) {
            keys.add(key);
        }
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            RefColumnInfo tempVar = new RefColumnInfo();
            tempVar.setColumnName(currnetAlias + "." + trans2DbColumn(key));
            tempVar.setTransProcesser(getContainColumns().getItem(key).getTypeTransProcesser());
            tempVar.setColumnType(getContainColumns().getItem(key).getColumnType());
            associationColumns.put(key, tempVar);
        }

        initAssociateColumnInfo(associationInfo, associationColumns);

        String sourceColumnName = trans2DbColumnWithAlias(associationInfo.getSourceColumn());
        return String.format(getJoinTableName(), tableName, sourceColumnName, keyDbColumnName);

    }

    private void addTableAlias(ArrayList<String> tableAlias) {
        tableAlias.add(getWrappedTableAlias());
    }

    private String getTableAlias4Association(ArrayList<String> tableAlias) {
        if (!tableAlias.contains(getWrappedTableAlias())) {
            tableAlias.add(getWrappedTableAlias());
            return getWrappedTableAlias();
        }

        int index = 1;
        while (true) {
            if (tableAlias.contains(getWrappedTableAlias(true) + index)) {
                index++;
            } else {
                tableAlias.add(getWrappedTableAlias(true) + index);
                return getWrappedTableAlias(true) + index;
            }
        }
    }

    public String getTableName() {
        return innerGetTableName() + " " + getWrappedTableAlias();
    }

    private void initAssociateColumnInfo(AssociationInfo associationInfo, HashMap<String, RefColumnInfo> associationColumns) {
        if (!AssoMapping.containsKey(associationInfo.getSourceColumn())) {
            AssoMapping.put(associationInfo.getSourceColumn(), new HashMap<String, String>());
        }

        for (Map.Entry<String, String> refColumnItem : associationInfo.getRefColumns().entrySet()) {
            if (!AssoMapping.get(associationInfo.getSourceColumn()).containsKey(refColumnItem.getValue())) {
                AssoMapping.get(associationInfo.getSourceColumn()).put(refColumnItem.getValue(), refColumnItem.getKey());
            }
            if (getContainColumns().contains(refColumnItem.getKey())) {
                DbColumnInfo columnInfo = getContainColumns().getItem(refColumnItem.getKey());
                RefColumnInfo refColumnInfo = associationColumns.get(refColumnItem.getValue());
                columnInfo.setDbColumnName(refColumnInfo.getColumnName());
                ITypeTransProcesser tempVar = refColumnInfo.getTransProcesser();
                columnInfo.setTypeTransProcesser((ITypeTransProcesser) ((tempVar instanceof ITypeTransProcesser) ? tempVar : null));
                columnInfo.setColumnType(refColumnInfo.getColumnType());
                associationColumns.remove(refColumnItem.getValue());
            } else {
                //TODO：改成抛异常
                if (!associationColumns.containsKey(refColumnItem.getValue())) {
                    continue;
                }
                DbColumnInfo refColumnInfo =  ((EntityRelationalAdaptor)(((BaseRootRepository)associationInfo.getRefRepository()).getEntityDac(associationInfo.getNodeCode()).getEntityAdaptor())).getContainColumns().getItem(refColumnItem.getValue());
                ITypeTransProcesser tempVar2 = associationColumns.get(refColumnItem.getValue()).getTransProcesser();
                DbColumnInfo tempVar3 = new DbColumnInfo();
                tempVar3.setColumnName(refColumnItem.getKey());
                tempVar3.setDbColumnName(associationColumns.get(refColumnItem.getValue()).getColumnName());
                if(refColumnInfo==null) {
                    tempVar3.setTypeTransProcesser((ITypeTransProcesser) ((tempVar2 instanceof ITypeTransProcesser) ? tempVar2 : null));
                    tempVar3.setColumnType(associationColumns.get(refColumnItem.getValue()).getColumnType());

                }
                else {
                    tempVar3.setTypeTransProcesser(refColumnInfo.getTypeTransProcesser());
                    tempVar3.setColumnType(refColumnInfo.getColumnType());
                }
//                tempVar3.setTypeTransProcesser((ITypeTransProcesser) ((tempVar2 instanceof ITypeTransProcesser) ? tempVar2 : null));
//                tempVar3.setColumnType(associationColumns.get(refColumnItem.getValue()).getColumnType());
                tempVar3.setIsAssociateRefElement(true);
                tempVar3.setBelongElementLabel(associationInfo.getSourceColumn());
                DbColumnInfo columnInfo = tempVar3;
                getContainColumns().add(columnInfo);
                associationColumns.remove(refColumnItem.getValue());
            }

        }

        for (Map.Entry<String, RefColumnInfo> associationColumn : associationColumns.entrySet()) {
            DbColumnInfo tempVar4 = new DbColumnInfo();
            tempVar4.setColumnName(associationInfo.getSourceColumn() + "_" + associationColumn.getKey());
            tempVar4.setDbColumnName(associationColumn.getValue().getColumnName());
            tempVar4.setTypeTransProcesser((ITypeTransProcesser) ((associationColumn.getValue().getTransProcesser() instanceof ITypeTransProcesser) ? associationColumn.getValue().getTransProcesser() : null));
            tempVar4.setColumnType(associationColumn.getValue().getColumnType());
            tempVar4.setIsAssociateRefElement(true);
            tempVar4.setBelongElementLabel(associationInfo.getSourceColumn());

            DbColumnInfo columnInfo = tempVar4;
            getContainColumns().add(columnInfo);
            if (!AssoMapping.get(associationInfo.getSourceColumn()).containsKey(associationColumn.getKey())) {
                AssoMapping.get(associationInfo.getSourceColumn()).put(associationColumn.getKey(), associationInfo.getSourceColumn() + "_" + associationColumn.getKey());
            }
        }
    }

    // endregion

    public final boolean isDatasEffective(ArrayList<String> dataIds, RefObject<ArrayList<String>> missingDataIds) {
        missingDataIds.argvalue = new ArrayList<String>();
        if (dataIds == null || dataIds.isEmpty()) {
            return true;
        }
        if (dataIds.size() == 1) {
            boolean result = isDataEffective(dataIds.get(0));
            if (result == false) {
                missingDataIds.argvalue.add(dataIds.get(0));
            }
            return result;
        } else {
            int batchCount = 5000;
            if(dataIds != null && dataIds.size() > batchCount){
                int times = dataIds.size()%batchCount == 0 ? dataIds.size()/batchCount : dataIds.size()/batchCount + 1;
                for(int i=1 ;i<= times;i++){
                    int endIndex = i == times ? dataIds.size() : batchCount*i;
                    List<String> tempList = dataIds.subList(batchCount* (i-1), endIndex);

                    String sql = String.format("SELECT COUNT(1) FROM %1$s WHERE %2$s IN %3$s", innerGetTableName(), getContainColumns().getPrimaryKey().getDbColumnName(), getInFilter(tempList, getContainColumns().getPrimaryKey().getDbColumnName()));
                    List<DbParameter> parameters = new ArrayList<DbParameter>();
                    if(getLogicDeleteInfo().isEnableLogicDelete()){
                        sql += " and " + getLogicDeleteInfo().getLabelId() + " =?0";
                        parameters.add(buildParam(getLogicDeleteInfo().getLabelId(), GspDbDataType.Char, "0"));
                    }
                    Query query = buildQueryManager(sql, parameters);
                    Integer count= Integer.valueOf(query.getResultList().get(0).toString());
                    if (count == tempList.size()) {
                        return true;
                    }
                    missingDataIds.argvalue = getMissingDataIds((ArrayList<String>) tempList);
                    if (missingDataIds.argvalue != null && missingDataIds.argvalue.size() != 0) {
                        return false;
                    }
                }
            }
            else{
                String sql = String.format("SELECT COUNT(1) FROM %1$s WHERE %2$s IN %3$s", innerGetTableName(), getContainColumns().getPrimaryKey().getDbColumnName(), getInFilter(dataIds, getContainColumns().getPrimaryKey().getDbColumnName()));
                List<DbParameter> parameters = new ArrayList<DbParameter>();
                if(getLogicDeleteInfo().isEnableLogicDelete()){
                    sql += " and " + getLogicDeleteInfo().getLabelId() + " =?0";
                    parameters.add(buildParam(getLogicDeleteInfo().getLabelId(), GspDbDataType.Char, "0"));
                }
                Query query = buildQueryManager(sql, parameters);
                Integer count= Integer.valueOf(query.getResultList().get(0).toString());
                if (count == dataIds.size()) {
                    return true;
                }
                missingDataIds.argvalue = getMissingDataIds(dataIds);
                if (missingDataIds.argvalue != null && missingDataIds.argvalue.size() != 0) {
                    return false;
                }
            }
            return true;
        }
    }
    private void writeLog(String message)
    {
        SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
        Date date = new Date(System.currentTimeMillis());

        System.out.println(message+" at "+formatter.format(date));
    }

    public final   boolean isRef( String dataId, String propertyName)
    {
        List<String> tables = innerGetTableNames();
        int totalCount = 0;
        if(tables != null && tables.size() >0){
            for(String tableName : tables){
                totalCount += getRefDataCount(tableName, dataId, propertyName);
            }
        }
        boolean result = totalCount > 0;
        return result;
    }

    private int getRefDataCount(String tableName, String dataId, String propertyName){
        String sql = "Select count(1) from " + tableName + " where " + getContainColumns().getItem(propertyName).getDbColumnName() + " =?0";
        List<DbParameter> parameters = new ArrayList<DbParameter>();
        parameters.add(new DbParameter("Id", getContainColumns().getPrimaryKey().getColumnType(), dataId));
        if(getLogicDeleteInfo().isEnableLogicDelete()){
            sql += " and " + getLogicDeleteInfo().getLabelId() + " =?1";
            parameters.add(buildParam(getLogicDeleteInfo().getLabelId(), GspDbDataType.Char, "0"));
        }
        int res = 0;
        try{
            Query query = buildQueryManager(sql, parameters);
            res = Integer.valueOf(query.getResultList().get(0).toString());
        }
        catch (Exception ex){
            logger.error("获取data个数出错sql:" + sql);
            throw new RuntimeException("检查["+tableName+"]的字段["+propertyName+"]引用时出错");
        }
        return res;
    }
    public final boolean isDatasEffective(ArrayList<String> dataIds, RefObject<ArrayList<String>> missingDataIds, String propName) {
        missingDataIds.argvalue = new ArrayList<String>();
        if (dataIds == null || dataIds.isEmpty()) {
            return true;
        }
        if (dataIds.size() == 1) {
            boolean result = isDataEffective(dataIds.get(0), propName);
            if (result == false) {
                missingDataIds.argvalue.add(dataIds.get(0));
            }
            return result;
        } else {
            int batchCount = 5000;
            String targetDbName = getContainColumns().getItem(propName).getDbColumnName();
            if(dataIds != null && dataIds.size() > batchCount){
                int times = dataIds.size()%batchCount == 0 ? dataIds.size()/batchCount : dataIds.size()/batchCount + 1;
                for(int i=1 ;i<= times;i++){
                    int endIndex = i == times ? dataIds.size() : batchCount*i;
                    List<String> tempList = dataIds.subList(batchCount* (i-1), endIndex);
                    String sql = String.format("SELECT %1$s FROM %2$s WHERE %3$s IN %4$s", targetDbName, innerGetTableName(), targetDbName, FilterUtil.buildInCondition(tempList, false, propName));
                    List<DbParameter> parameters = new ArrayList<DbParameter>();
                    if(getLogicDeleteInfo().isEnableLogicDelete()){
                        sql += " and " + getLogicDeleteInfo().getLabelId() + " =?0";
                        parameters.add(buildParam(getLogicDeleteInfo().getLabelId(), GspDbDataType.Char, "0"));
                    }
                    Query query = buildQueryManager(sql, parameters);
                    HashSet checkNum = new HashSet<>(query.getResultList());
                    if (checkNum.size() >= dataIds.size()) {
                        return true;
                    }
                    missingDataIds.argvalue = getMissingDataIds(tempList, propName);
                    if (missingDataIds.argvalue != null && missingDataIds.argvalue.size() != 0) {
                        return false;
                    }
                }
            }
            else{
                String sql = String.format("SELECT %1$s FROM %2$s WHERE %3$s IN %4$s", targetDbName, innerGetTableName(), targetDbName, FilterUtil.buildInCondition(dataIds, false, propName));
                List<DbParameter> parameters = new ArrayList<DbParameter>();
                if(getLogicDeleteInfo().isEnableLogicDelete()){
                    sql += " and " + getLogicDeleteInfo().getLabelId() + " =?0";
                    parameters.add(buildParam(getLogicDeleteInfo().getLabelId(), GspDbDataType.Char, "0"));
                }
                Query query = buildQueryManager(sql, parameters);
                HashSet checkNum = new HashSet<>(query.getResultList());
                if (checkNum.size() >= dataIds.size()) {
                    return true;
                }
                missingDataIds.argvalue = getMissingDataIds(dataIds, propName);
                if (missingDataIds.argvalue != null && missingDataIds.argvalue.size() != 0) {
                    return false;
                }
            }
            return true;
        }
    }

    private ArrayList<String> getMissingDataIds(ArrayList<String> dataIds) {
        String sql = "Select " + getPrimaryKey() + " from " + innerGetTableName() + " where " + getPrimaryKey() + " in " + getInFilter(dataIds, getContainColumns().getPrimaryKey().getDbColumnName());
        List<DbParameter> dbPars = null;
        if(getLogicDeleteInfo().isEnableLogicDelete()){
            sql += " and " + getLogicDeleteInfo().getLabelId() + " =?0";
            dbPars = new ArrayList<>();
            dbPars.add(buildParam(getLogicDeleteInfo().getLabelId(), GspDbDataType.Char, "0"));
        }
        ArrayList<String> dbDataIds = getDataIds(sql, dbPars);
        ArrayList<String> missingDataIds = new ArrayList<String>();

        for (String item : dataIds) {
            if (dbDataIds.contains(item) == false) {
                missingDataIds.add(item);
            }
        }
        return missingDataIds;
    }

    private ArrayList<String> getMissingDataIds(List<String> dataIds, String propName) {
        String sql = "Select " + propName + " from " + innerGetTableName() + " where " + propName + " in " + getInFilter(dataIds, propName);
        List<DbParameter> dbPars = null;
        if(getLogicDeleteInfo().isEnableLogicDelete()){
            sql += " and " + getLogicDeleteInfo().getLabelId() + " =?0";
            dbPars = new ArrayList<>();
            dbPars.add(buildParam(getLogicDeleteInfo().getLabelId(), GspDbDataType.Char, "0"));
        }
        ArrayList<String> dbDataIds = getDataIds(sql, dbPars);
        ArrayList<String> missingDataIds = new ArrayList<String>();

        for (String item : dataIds) {
            if (dbDataIds.contains(item) == false) {
                missingDataIds.add(item);
            }
        }
        return missingDataIds;
    }

    private ArrayList<String> getDataIds(String sql, List<DbParameter> parameters) {

        Query query = buildQueryManager(sql, parameters);
        List<Object[]> result = query.getResultList();
        ArrayList<String> list = new ArrayList<String>();
        for (int i = 0; i < result.size(); i++) {
            if(result.get(i) instanceof Object[]){
                list.add(String.valueOf(result.get(i)[0]));
            }
            else {
                list.add(String.valueOf(result.get(i)));
            }
        }
        return list;
    }

    private String getSqlInString(ArrayList<String> dataIds) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < dataIds.size(); i++) {
            String item = dataIds.get(i);
            sb.append(String.format("'%1$s'", item));
            if (i != dataIds.size() - 1) {
                sb.append(",");
            }
        }
        return sb.toString();
    }

    private boolean isDataEffective(String dataID) {
        String sql = "Select count(1) from " + innerGetTableName() + " where " + getContainColumns().getPrimaryKey().getDbColumnName() + " =?0";
        List<DbParameter> parameters = new ArrayList<DbParameter>();
        parameters.add(new DbParameter("Id", getContainColumns().getPrimaryKey().getColumnType(), dataID));
        if(getLogicDeleteInfo().isEnableLogicDelete()){
            sql += " and " + getLogicDeleteInfo().getLabelId() + " =?1";
            parameters.add(buildParam(getLogicDeleteInfo().getLabelId(), GspDbDataType.Char, "0"));
        }
        Query query = buildQueryManager(sql, parameters);

        return Integer.valueOf(query.getResultList().get(0).toString()) > 0;
    }

    private boolean isDataEffective(String dataID, String propName) {
        String sql = "Select count(1) from " + innerGetTableName() + " where " + getContainColumns().getItem(propName).getDbColumnName() + " =?0";
        List<DbParameter> parameters = new ArrayList<DbParameter>();
        parameters.add(new DbParameter(propName, getContainColumns().getItem(propName).getColumnType(), dataID));
        if(getLogicDeleteInfo().isEnableLogicDelete()){
            sql += " and " + getLogicDeleteInfo().getLabelId() + " =?1";
            parameters.add(buildParam(getLogicDeleteInfo().getLabelId(), GspDbDataType.Char, "0"));
        }
        Query query = buildQueryManager(sql, parameters);

        return Integer.valueOf(query.getResultList().get(0).toString()) > 0;
    }

    protected INestedRepository getNestedRepository(String configId){
        if(!nestedRepositories.containsKey(configId)){
            synchronized (netstRepositoryLock){
                if(!nestedRepositories.containsKey(configId)){
                    nestedRepositories.put(configId, com.inspur.edp.udt.api.UdtManagerUtils.getUdtRepositoryFactory().createRepository(configId));
                }
            }
        }
        return nestedRepositories.get(configId);
    }
    protected String buildMessage(String message) {
        String warningMessage= I18nResourceUtil.getResourceItemValue("pfcommon","cef_exception.properties","Gsp_Cef_Retrieve_0001");
        return String.format(warningMessage, message);
    }

    public  List<String> getDistinctFJM(String fjnPropertyName, EntityFilter filter,ArrayList<AuthorityInfo> authorityInfos,Integer parentLayer)
    {
        String tableName = getQueryTableNameWithAuthority(authorityInfos,filter);
        StringBuilder sql = new StringBuilder();
        sql.append(String.format("SELECT  %1$s FROM %2$s ", getDistinctFJMSql(fjnPropertyName,parentLayer), tableName));
        ArrayList<DbParameter> parameter = new ArrayList<DbParameter>();
        String condition = buildWhereCondition(getDB(), filter.getFilterConditions(), parameter);
        String sort = buildOrderByCondition(filter.getSortConditions());
        if (condition != null && condition.length() > 0) {
            sql.append(String.format(" WHERE %1$s", condition));
        }
//        if (sort != null && sort.length() > 0) {
//            sql.append(String.format(" Order By %1$s", sort));
//        }
        Query query = buildQueryManager(formatMultiLang( sql.toString()), parameter);
        List<Object> resultSet = null;
        try {
            resultSet = query.getResultList();
        } catch (Exception ex) {
            logger.error("tablealias:" + getTableAlias() + " 出错sql:" + sql);
            throw ex;
        }
        if(resultSet==null||resultSet.size()==0)
            return new ArrayList<>();
        List<String> fjms = new ArrayList<>();
        Object value=null;
        for(Object result:resultSet)
        {
            value =result;
            if(value ==null)
                continue;
            fjms.add((String) value);
        }
        return fjms;
    }

    private String getDistinctFJMSql(String fjnPropertyName,Integer parentLayer) {
        DbColumnInfo dbColumnInfo = getContainColumns().getItem(fjnPropertyName);
        if (dbColumnInfo == null)
            throw new RuntimeException("找不到列：" + fjnPropertyName);
        fjnPropertyName = trans2DbColumnWithAlias(dbColumnInfo.getColumnName());
        switch (CAFContext.current.getDbType()) {
            case SQLServer:
                return "distinct(substring(" + fjnPropertyName + ",0," + ((parentLayer + 1) * 4 + 1) + "))";
            case HighGo:
                return "distinct(substring(" + fjnPropertyName + " from 0 for " + ((parentLayer + 1) * 4 + 1) + "))";
            case Gbase:
            case Oscar:
                return "distinct(substring(" + fjnPropertyName + ",0," + (parentLayer + 1) * 4 + "))";
            case Kingbase:
                return "distinct(substring(" + fjnPropertyName + ",1," + (parentLayer + 1) * 4 + "))";
            case Oracle:
                return "distinct(substr(" + fjnPropertyName + ",0," + (parentLayer + 1) * 4 + "))";
            case PgSQL:
                return "distinct(substring(" + fjnPropertyName + " from 0 for " + ((parentLayer + 1) * 4 + 1) + "))";
            case DM:
                return "distinct(substring(" + fjnPropertyName + " from 0 for " + ((parentLayer + 1) * 4) + "))";
            case MySQL:
                return "distinct(substring(" + fjnPropertyName + ",1," + (parentLayer + 1) * 4 + "))";
            case DB2:
                return "distinct(substr(" + fjnPropertyName + ",1," + (parentLayer + 1) * 4 + "))";
            default:
                throw new RuntimeException();
        }
    }
}
